From: Sebastian Ramacher Date: Fri, 12 Sep 2025 21:00:35 +0000 (+0200) Subject: cmus (2.12.0-2) unstable; urgency=medium X-Git-Tag: archive/raspbian/2.12.0-2+rpi1^2~16 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks:///%22http:/www.example.com/cgi/%22https:/%22bookmarks:/?a=commitdiff_plain;h=0b4019b8b3b04b86b6c2d9f0b245cfe14848219f;p=cmus.git cmus (2.12.0-2) unstable; urgency=medium * Team upload * Fix build with ffmpeg 8.0 (Closes: #1115013) [dgit import unpatched cmus 2.12.0-2] --- 0b4019b8b3b04b86b6c2d9f0b245cfe14848219f diff --cc debian/changelog index 0000000,0000000..38283a5 new file mode 100644 --- /dev/null +++ b/debian/changelog @@@ -1,0 -1,0 +1,598 @@@ ++cmus (2.12.0-2) unstable; urgency=medium ++ ++ * Team upload ++ * Fix build with ffmpeg 8.0 (Closes: #1115013) ++ ++ -- Sebastian Ramacher Fri, 12 Sep 2025 23:00:35 +0200 ++ ++cmus (2.12.0-1) unstable; urgency=medium ++ ++ * Team upload. ++ ++ [ Philippe SWARTVAGHER ] ++ * New upstream version 2.12.0 (Closes: #1087737) ++ + Refresh patches ++ * Bump standards-version to 4.7.2: no change needed ++ * d/rules: remove as-needed linker flag ++ * Add lintian override for library-not-linked-against-libc ++ of usr/lib/cmus/op/sndio.so ++ * Add patch to use hardening flags to build Doc/ttman ++ ++ [ Helmut Grohne ] ++ * Fix FTCBFS: Fix build/host confusion. (Closes: #954749) ++ ++ [ Dylan Aïssi ] ++ * Convert debian/copyright to DEP5 ++ ++ -- Philippe SWARTVAGHER Sat, 15 Mar 2025 22:56:48 +0100 ++ ++cmus (2.11.0-1) unstable; urgency=medium ++ ++ * Team upload ++ * New upstream version 2.11.0 ++ - Fix build with ffmpeg 7.0 (Closes: #1072405) ++ * debian/patches: Refresh patches ++ * debian/control: ++ - Bump Standards-Version ++ - Use pkgconf ++ - Use openmpt's modplug ++ - Use libncurses-dev ++ ++ -- Sebastian Ramacher Sun, 09 Jun 2024 23:45:17 +0200 ++ ++cmus (2.10.0-4) unstable; urgency=medium ++ ++ * Team upload ++ * debian/patches: Apply upstream patch to fix compatibility with ffmpeg 6.0 ++ (Closes: #1041375) ++ ++ -- Sebastian Ramacher Thu, 27 Jul 2023 21:00:31 +0200 ++ ++cmus (2.10.0-3) unstable; urgency=medium ++ ++ * Team upload ++ * debian/control: Bump Standards-Version ++ * debian/: Remove roar support (Closes: #1030661) ++ ++ -- Sebastian Ramacher Tue, 07 Feb 2023 09:20:50 +0100 ++ ++cmus (2.10.0-2) unstable; urgency=medium ++ ++ * Team upload ++ * Add a patch from upstream to fix a freeze when exiting cmus ++ ++ -- Philippe SWARTVAGHER Sun, 31 Jul 2022 22:01:04 +0200 ++ ++cmus (2.10.0-1) unstable; urgency=medium ++ ++ * Team upload ++ ++ [ Jenkins ] ++ * Remove constraints unnecessary since buster ++ ++ [ Philippe SWARTVAGHER ] ++ * New upstream version 2.10.0 ++ * Bump d/watch version ++ * Bump standards-version to 4.6.1 ++ * Add a patch to fix a typo spotted by Lintian ++ ++ -- Philippe SWARTVAGHER Wed, 13 Jul 2022 20:40:37 +0200 ++ ++cmus (2.9.1-1) unstable; urgency=medium ++ ++ * Team upload ++ * New upstream release ++ ++ -- Sebastian Ramacher Fri, 22 Jan 2021 22:28:04 +0100 ++ ++cmus (2.9.0-1) unstable; urgency=medium ++ ++ * Team upload ++ ++ [ Debian Janitor ] ++ * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, ++ Repository-Browse. ++ ++ [ Patrick Gaskin ] ++ * Fix missing dependency for MPRIS support ++ ++ [ Sebastian Ramacher ] ++ * New upstream release ++ * debian/control: ++ - Bump Standards-Version ++ - Bump debhelper compat to 13 ++ - Set RRR: no ++ * debian/patches/12-typos.patch: Removed, fixed upstream ++ ++ -- Sebastian Ramacher Tue, 19 Jan 2021 20:15:26 +0100 ++ ++cmus (2.8.0-2) unstable; urgency=medium ++ ++ * Set build flags via /usr/share/dpkg/buildflags.mk ++ * Link with -latomic to fix FTBFS on various architectures (Closes: #935678) ++ ++ -- Ryan Kavanagh Sat, 07 Sep 2019 10:37:13 -0400 ++ ++cmus (2.8.0-1) unstable; urgency=medium ++ ++ [ Ondřej Nový ] ++ * Use debhelper-compat instead of debian/compat ++ ++ [ Helmut Grohne ] ++ * Fix FTCBFS: Supply a cross environment to ./configure. (Closes: #911163) ++ ++ [ Ryan Kavanagh ] ++ * New upstream version 2.8.0 (Closes: #932107, #783498) ++ + Update copyright file with new holders ++ + Drop 12-ffmpeg-4.0.patch (applied upstream) ++ + Refresh patches ++ * Drop outdated get-orig-source target from rules ++ * Fix typos in source, 12-typos.patch ++ * Enable hardening ++ * Bump debphelper compat to 12 ++ * Bump standards-version to 4.4.0 ++ * cmus-plugin-ffmpeg (<< 2.8.0) breaks cmus (>= 2.8.0) ++ ++ -- Ryan Kavanagh Sat, 17 Aug 2019 14:51:27 -0400 ++ ++cmus (2.7.1+git20160225-2) unstable; urgency=medium ++ ++ * Team upload. ++ ++ [ James Cowgill ] ++ * Add upstream patch to fix FTBFS with FFmpeg 4.0. (Closes: #888384) ++ * d/changelog: Remove trailing blank line. ++ ++ [ Alessio Treglia ] ++ * Remove myself from the Uploaders field. ++ ++ [ Ondřej Nový ] ++ * d/control: Set Vcs-* to salsa.debian.org. ++ * d/changelog: Remove trailing whitespaces. ++ ++ [ Felipe Sateler ] ++ * Change maintainer address to debian-multimedia@lists.debian.org. ++ ++ -- James Cowgill Thu, 17 May 2018 11:34:35 +0100 ++ ++cmus (2.7.1+git20160225-1) unstable; urgency=medium ++ ++ * Team upload. ++ * New upstream snapshot. ++ - Fix build against ffmpeg 3.0. (Closes: #810557) ++ * debian/patches/{01_config.mk.diff,02_link_avcodec.patch}: Removed, applied ++ upstream. ++ * debian/control: ++ - Bump Standards Version. ++ - Update Vcs-Git. ++ ++ -- Sebastian Ramacher Sun, 06 Mar 2016 21:37:57 +0100 ++ ++cmus (2.7.1-1) unstable; urgency=medium ++ ++ * Team upload. ++ ++ [ Alessio Treglia ] ++ * Demote extra plugins to Suggests (Closes: #789256) ++ * Refresh patchset for 2.6.0. ++ ++ [ Sebastian Ramacher ] ++ * New upstream release. (Closes: #779335, #792134) ++ - Use libswresample instead of libavresample. (Closes: #805169, #805109) ++ * Update path for README ++ * debian/control: ++ - Add libdiscid-dev, libopusfile-dev, libsamplerate0-dev and libjack-dev ++ to Build-Depends. ++ - Change libavresample-dev to libswresample-dev in Build-Depends and add ++ libavcodec-dev. ++ - Add bash-completion to Build-Depends. ++ - Bump Standards-Version to 3.9.6. ++ - Update Vcs-Browser. ++ - Make cmus-plugin-ffmpeg depend on the same version of cmus (Closes: ++ #695072) ++ * debian/cmus.install: Install zsh completion. ++ * debian/cmus.bash-completion: Install bash completion. ++ * debian/rules: ++ - Build with --parallel and --with bash-completion. ++ - Handle jack shlibs similar to pulse. ++ * debian/patches: ++ - libav10.patch: Removed, no longer needed. ++ - 02_link_avcodec.patch: Functions from libavcodec are used so make sure ++ the ffmpeg plugin is linked against libavcodec. ++ ++ -- Sebastian Ramacher Sun, 15 Nov 2015 19:24:52 +0100 ++ ++cmus (2.5.0-7) unstable; urgency=medium ++ ++ * Re-introduce Roaraudio support (Closes: #680745): ++ - debian/control: Add build-dependency on libroad-dev. ++ - debian/rules: Tune dpkg-shlibdeps call to move pulse and roar's ++ dependencies to Recommends. Made the whole mechanism slightly more ++ elegant. ++ * Enable CUE support. ++ * The project has moved to github, update the Homepage field accordingly. ++ * Update debian/watch, project has moved from sourceforge to github. ++ ++ -- Alessio Treglia Thu, 14 Aug 2014 13:45:10 +0100 ++ ++cmus (2.5.0-6) unstable; urgency=medium ++ ++ * Team upload. ++ * Upload to unstable. ++ ++ -- Sebastian Ramacher Sun, 11 May 2014 23:45:16 +0200 ++ ++cmus (2.5.0-5) experimental; urgency=low ++ ++ * Team upload. ++ * Compile against libav10 (Closes: #739301) ++ * Bump standards version ++ ++ -- Reinhard Tartler Mon, 24 Mar 2014 19:35:28 -0400 ++ ++cmus (2.5.0-4) unstable; urgency=low ++ ++ [ Ryan Kavanagh ] ++ * Patches were applied upstream ++ ++ [ Alessio Treglia ] ++ * Add patch to prevent FTBFS. (Closes: #724181) ++ ++ -- Alessio Treglia Sun, 06 Oct 2013 20:46:25 +0100 ++ ++cmus (2.5.0-3) unstable; urgency=low ++ ++ * Don't FTBFS due to missing config.mk (Closes: #720781), 01_config.mk.diff ++ * Fix typo in cmus binary, 02_fix_typo.diff ++ * Enable build hardening ++ + Bump debhelper version to 9.0.0 and compat to 9 ++ + Introduce 03_cppflags.diff to use CPPFLAGS; needed for function ++ fortification ++ + Override hardening-no-fortify-functions false positives ++ * Bump standards version to 3.9.4 ++ * Switch to canonical Vcs-* fields ++ * Enable verbose build logs ++ ++ -- Ryan Kavanagh Thu, 29 Aug 2013 13:48:30 -0400 ++ ++cmus (2.5.0-2) unstable; urgency=low ++ ++ * Upload to unstable. ++ ++ -- Alessio Treglia Sat, 11 May 2013 01:21:18 +0200 ++ ++cmus (2.5.0-1) experimental; urgency=low ++ ++ * New upstream release: ++ - CUE sheets support. ++ - cdio input plugin. ++ - support for WavPack `.wvc` correction files. ++ - new «zenburn» color scheme and text attributes (bold/reverse/...) ++ support for UI elements. ++ - improved tab completion, new scroll_offset and icecast_default_charset ++ options, even better tag parsing and compilations handling, and ++ numerous small enhancements all over the place. ++ * Build-depend on libcddb2-dev,libcdio-cdda-dev. ++ ++ -- Alessio Treglia Thu, 15 Nov 2012 00:28:20 +0000 ++ ++cmus (2.4.3-2) unstable; urgency=low ++ ++ [ Ryan Kavanagh ] ++ * Update my email address to @debian.org ++ * Drop DM-Upload-Allowed: yes, no longer needed ++ ++ [ Alessio Treglia ] ++ * Build cmus without roar support. (Closes: #675610) ++ * Bump Standards. ++ ++ -- Alessio Treglia Sat, 02 Jun 2012 20:07:57 +0200 ++ ++cmus (2.4.3-1) unstable; urgency=low ++ ++ * New upstream release. ++ ++ -- Alessio Treglia Sat, 03 Dec 2011 12:55:46 +0100 ++ ++cmus (2.4.2-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Drop 0001-fix-compile-error-for-new-versions-of-ffmpeg.patch, ++ applied upstream. ++ ++ -- Alessio Treglia Tue, 26 Jul 2011 10:13:25 +0200 ++ ++cmus (2.4.1-2) unstable; urgency=low ++ ++ * Add Ubuntu-specific patch to fix FTBFS with newest version of ffmpeg. ++ * Replace negated list of architectures with linux-any (Closes: #634706). ++ ++ -- Alessio Treglia Sat, 23 Jul 2011 10:48:29 +0200 ++ ++cmus (2.4.1-1) unstable; urgency=medium ++ ++ * New upstream release (Closes: #628422): ++ - Doc: add help for :shell ++ - ffmpeg: move up "config/ffmpeg.h" include ++ - fix two memleaks ++ - fix cache refresh bug ++ - configure: fix FLAC include path ++ - configure: fix ffmpeg header detection ++ - fix TCP/IP networking protocol ++ - fix segfault when hitting win-activate on empty tree ++ - display error if seeking failed ++ - fix segfault when using tqueue/lqueue ++ - fix lqueue command ++ - fix infinite loop when adding certain mp3 files ++ - fix reading of id3v2 tags at the end of files ++ - more fault-tolerant integer tag-reading ++ * Bump urgency to medium as the previous release was seriously buggy. ++ ++ -- Alessio Treglia Sun, 29 May 2011 19:18:48 +0200 ++ ++cmus (2.4.0-1) unstable; urgency=low ++ ++ * New upstream release "Easter egg": ++ - Mutt-like short filters. ++ - Live filtering. ++ - Resume support. ++ - Smarter string handling. ++ - Long format options, including ones for bitrate/codec. ++ - HTTP proxy support for streams via http_proxy environment variable. ++ - Less CPU wakeups during playback. ++ - New RoarAudio output plugin. ++ - Support for big-endian systems, lots of different audio sample formats, ++ almost any C compiler and unix-like OS out there. ++ - Various bugfixes. ++ - Full release notes are available at: ++ http://sourceforge.net/mailarchive/message.php?msg_id=27403242 ++ * debian/watch: Properly handle release-candidate,beta releases. ++ * Remove debian/patches directory, all patches have been applied upstream. ++ * Bump Standards. ++ ++ -- Alessio Treglia Tue, 26 Apr 2011 23:30:07 +0200 ++ ++cmus (2.3.5-1) unstable; urgency=low ++ ++ * New upstream release: ++ - Features gapless MP3 playback. ++ - Native PulseAudio support. ++ - Faster startup. ++ - Improve buildsystem. ++ * Refresh patches. ++ * Remo 21-missing_plugins.patch, applied upstream. ++ ++ -- Alessio Treglia Sat, 23 Apr 2011 09:56:57 +0200 ++ ++cmus (2.3.4-3) unstable; urgency=low ++ ++ * Handle missing dependencies more gracefully: ++ - cmus silently skips plugins with missing dependencies, and instead ++ outputs a debug message. Original patch by Johannes Weißl, already ++ accepted upstream. ++ ++ -- Alessio Treglia Fri, 01 Apr 2011 08:59:01 +0200 ++ ++cmus (2.3.4-2) unstable; urgency=low ++ ++ * Avoid to depend on several sound servers (Closes: #612887) and let ++ users choose to rely on the favorite one. ++ - debian/control: ++ + Add shlibs:Recommends field. ++ - debian/rules: ++ + Supply {dh_,dpkg-}shlibdeps with proper options to demote roar ++ and pulse audio dependencies to Recommends. ++ ++ -- Alessio Treglia Tue, 15 Mar 2011 12:46:03 +0100 ++ ++cmus (2.3.4-1) unstable; urgency=low ++ ++ [ Ryan Kavanagh ] ++ * New upstream release. ++ * Dropped 01_spelling_mistakes.diff, 02_cmus-tutorial_whatis.diff ++ and 03-terminal_corruption.patch (applied upstream). ++ * Refreshed 10-roaraudio_support.patch ++ * Bump my copyright ++ ++ [ Alessio Treglia ] ++ * Add DM-Upload-Allowed: yes. ++ ++ -- Ryan Kavanagh Tue, 22 Feb 2011 09:03:23 -0500 ++ ++cmus (2.3.3-4) unstable; urgency=low ++ ++ * Upload to unstable. ++ ++ -- Alessio Treglia Wed, 09 Feb 2011 12:05:49 +0100 ++ ++cmus (2.3.3-3) experimental; urgency=low ++ ++ * Add RoarOutput plugin (Closes: #609202), thanks to ++ Philipp Schafft for the patch. ++ * Add patch taken from upstream's git to fix segfault when adding to ++ queue. ++ * Build-depends on libroar-dev (>= 0.4~beta2). ++ ++ -- Alessio Treglia Mon, 17 Jan 2011 02:23:04 +0100 ++ ++cmus (2.3.3-2) unstable; urgency=low ++ ++ * Prevent terminal corruption on track change. ++ * debian/copyright: Update sources download location. ++ * Split cmus to provide smart dependencies (Closes: #442423). ++ * Bump Standards. ++ ++ -- Alessio Treglia Sun, 01 Aug 2010 12:26:08 +0200 ++ ++cmus (2.3.3-1) unstable; urgency=low ++ ++ [ Ryan Kavanagh ] ++ * New upstream release (Closes: #572284) ++ * Imported Upstream version 2.3.3 ++ * Changed to source format 3.0 source. Involved converting ++ dpatch->quilt and dropping dpatch B-D. ++ * Dropped 01_cmusffmpeg.diff, no longer needed. Upstream checks for ++ ffmpeg and falls back to libavcodec for us. ++ * Dropped 02_cmusstatusdisplay.diff, included upstream. ++ * Dropped Yavor's mpcdec patch. Upstream expanded on it, using his ++ code if building under MPC SV8, the old code otherwise. ++ * Updated debian/watch ++ * Updated copyright file with new copyright holders and download ++ location. ++ * This is a new upload, package will thus be rebuilt against libavformat. ++ (Closes: #568361). ++ * Dropped debian/patches directory ++ * Move to debhelper 7 rules ++ * Now standards-version 3.8.4 ++ * Fix debhelper-but-no-misc-depends lintian warning ++ * Override dh_auto_configure because upstream uses a homebrewed configure ++ script that doesn't accept --a=b style options ++ * Bump debhelper version to (>= 7.0.50~) because we're using override_dh_* ++ * Fix spelling mistakes in binary and documentation ++ (01_spelling_mistake.diff) ++ * Fix whatis entry for cmus-tutorial manpage (02_cmus-tutorial_whatis.diff) ++ * Added Julien Louis' and my own packaging copyright blurb to ++ debian/copyright. ++ ++ [ Alessio Treglia ] ++ * This isn't a non-maintainer upload, we adopt this (Closes: #587604). ++ * Add debian/gbp.conf file. ++ * debian/control: ++ - Add Vcs-* tags. ++ - Bump Standards. ++ - Lines should be shorter than 80 characters. ++ - Add myself to Uploaders field, I'll take care of sponsoring this in ++ future. ++ - Build-depend on pkg-config. ++ - Drop unnecessary Recommends field. ++ * Drop aRTs support as it is no longer maintained. ++ * Add PulseAudio support. ++ * debian/rules: ++ - Call configure script instead of relying on dh_auto_configure. ++ * Drop README.source, we don't rely on dpatch as patch system. ++ * Update debian/copyright. ++ ++ -- Alessio Treglia Sun, 04 Jul 2010 20:06:58 +0200 ++ ++cmus (2.2.0-4.1) unstable; urgency=low ++ ++ * NMU ++ * Patch from Yavor Doganov to port cmus to the new mpcdec API, ++ thereby allowing cmus to build from source again. ++ closes: #476382, #552820. ++ ++ -- Clint Adams Sun, 31 Jan 2010 00:03:40 -0500 ++ ++cmus (2.2.0-4) unstable; urgency=low ++ ++ * Updated debian/watch file Closes: #449897 ++ - Thanks to Raphael Geissert ++ * Fix the ffmpeg/avcodec.h includes Closes: #517570 ++ - Thanks to Cyril Brulebois ++ * Added Recommends libasound2, libartsc0, libao2 Closes: #439719 ++ * Added Depends line in debian/control ++ * Added dpatch on Build-Depends on debian/control ++ * Deleted commented lines on debian/rules ++ * Update debian/rules for dpatch dependence ++ * Changed debian/control ++ - Standard-Version to 3.8.1 ( was 3.8.0 ) ++ - Added debian/README.source ++ - Updated to debhelper to 7 ++ - Updated debian/compat (was 5) ++ - Added Homepage field ++ ++ -- Carlos Eduardo Sotelo Pinto (krlos) Thu, 19 Mar 2009 13:38:16 -0500 ++ ++cmus (2.2.0-3) unstable; urgency=low ++ ++ * Acknowledging NMU. Closes: #509277. ++ ++ -- Carlos Eduardo Sotelo Pinto (krlos) Mon, 29 Dec 2008 22:01:01 +0100 ++ ++cmus (2.2.0-2) unstable; urgency=low ++ ++ * New maintainer. Closes: #484734 ++ * Changed debian/control ++ - Standard-Version to 3.8.0 ( was 3.7.2 no changes needed ) ++ ++ -- Carlos Eduardo Sotelo Pinto (krlos) Wed, 03 Sep 2008 17:46:50 -0500 ++ ++cmus (2.2.0-1.1) unstable; urgency=high ++ ++ * Non-maintainer upload by the Security Team. ++ * Modify example script cmus-status-display to write the current ++ status to .cmus-status in the user's home instead of /tmp/cmus-status, ++ since the latter could lead to symlink attacks. CVE-2008-5375 ++ (Closes: #509277) ++ ++ -- Moritz Muehlenhoff Sun, 28 Dec 2008 14:57:06 +0100 ++ ++cmus (2.2.0-1) unstable; urgency=low ++ ++ * New upstream release ++ * Add libwavpack-dev and libavformat.dev to Build-Depends ++ * Update debian/copyright ++ ++ -- Julien Louis Fri, 27 Jul 2007 21:54:36 +0200 ++ ++cmus (2.1.0-2) unstable; urgency=low ++ ++ * Rebuild against libflac8 (Closes: #426638). ++ ++ -- Julien Louis Mon, 04 Jun 2007 22:56:58 +0200 ++ ++cmus (2.1.0-1) unstable; urgency=low ++ ++ * New upstream release (closes: #399965). ++ * Updated debian/copyright ++ * Added libfaad-dev to Build-Depends ++ ++ -- Julien Louis Thu, 21 Dec 2006 20:25:59 +0100 ++ ++cmus (2.0.4-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Added debian/watch file. ++ * Build-Depends agains libasound2-dev (>= 1.0.11). ++ ++ -- Julien Louis Wed, 23 Aug 2006 03:34:04 +0200 ++ ++cmus (2.0.3-3) unstable; urgency=low ++ ++ * Drop libasound2-dev Build Dependency on non-linux arches ++ (Closes: #377885). ++ ++ -- Julien Louis Wed, 12 Jul 2006 01:06:02 +0200 ++ ++cmus (2.0.3-2) unstable; urgency=low ++ ++ * Move all dh_* helper stuff in the binary-arch target (Closes: #376320). ++ * Remove debian/patches/01_asciidoc_xsl_path.dpatch since it is not usefull. ++ * Remove dpatch from Build-Depends. ++ ++ -- Julien Louis Sun, 2 Jul 2006 14:16:03 +0200 ++ ++cmus (2.0.3-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Remove asciidoc, docbook-xsl, doxbook-xml ans xsltproc from Build-Depends. ++ * Add libartsc0-dev and libao-dev to Build-Depends. ++ ++ -- Julien Louis Sun, 18 Jun 2006 17:26:44 +0200 ++ ++cmus (2.0.2-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Remove ASCIIDOC patch since upstream now search for ++ /etc/asciidoc/docbook-xsl/. ++ * Add docbook-xml to Build-Depends. ++ * Bump Standards-Version no change needed. ++ * Added REAMDE.Debian ++ ++ -- Julien Louis Tue, 30 May 2006 22:12:01 +0200 ++ ++cmus (2.0.0-1) unstable; urgency=low ++ ++ * Initial release (Closes: #340000) ++ ++ -- Julien Louis Mon, 7 Nov 2005 18:19:55 +0100 diff --cc debian/cmus.bash-completion index 0000000,0000000..ca9c5f2 new file mode 100644 --- /dev/null +++ b/debian/cmus.bash-completion @@@ -1,0 -1,0 +1,1 @@@ ++contrib/cmus.bash-completion cmus diff --cc debian/cmus.install index 0000000,0000000..cb199e1 new file mode 100644 --- /dev/null +++ b/debian/cmus.install @@@ -1,0 -1,0 +1,2 @@@ ++usr ++contrib/_cmus usr/share/zsh/vendor-completions diff --cc debian/cmus.lintian-overrides index 0000000,0000000..4ccc128 new file mode 100644 --- /dev/null +++ b/debian/cmus.lintian-overrides @@@ -1,0 -1,0 +1,4 @@@ ++cmus: hardening-no-fortify-functions usr/lib/cmus/ip/flac.so ++ ++## This library actually doesn't directly call any libc function ++cmus: library-not-linked-against-libc [usr/lib/cmus/op/sndio.so] diff --cc debian/control index 0000000,0000000..d33178e new file mode 100644 --- /dev/null +++ b/debian/control @@@ -1,0 -1,0 +1,77 @@@ ++Source: cmus ++Section: sound ++Priority: optional ++Maintainer: Debian Multimedia Maintainers ++Uploaders: ++ Ryan Kavanagh ++Build-Depends: ++ debhelper-compat (= 13), ++ bash-completion, ++ libao-dev, ++ libasound2-dev [linux-any], ++ libavcodec-dev, ++ libavformat-dev, ++ libswresample-dev, ++ libcddb2-dev, ++ libcdio-cdda-dev, ++ libcue-dev, ++ libdiscid-dev, ++ libfaad-dev, ++ libflac-dev, ++ libjack-dev, ++ libmad0-dev, ++ libmpcdec-dev, ++ libncurses-dev, ++ libopenmpt-modplug-dev, ++ libopusfile-dev, ++ libpulse-dev, ++ libsamplerate0-dev, ++ libsystemd-dev, ++ libvorbis-dev, ++ libwavpack-dev, ++ pkgconf ++Standards-Version: 4.7.2 ++Homepage: https://cmus.github.io/ ++Vcs-Git: https://salsa.debian.org/multimedia-team/cmus.git ++Vcs-Browser: https://salsa.debian.org/multimedia-team/cmus ++Rules-Requires-Root: no ++ ++Package: cmus ++Architecture: any ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends} ++Recommends: ++ cmus-plugin-ffmpeg ++Suggests: ++ ${shlibs:Suggests} ++Breaks: cmus-plugin-ffmpeg (<< 2.8.0) ++Description: lightweight ncurses audio player ++ C* Music Player is a modular and very configurable ncurses-based audio player. ++ It has some interesting features like configurable colorscheme, mp3 and ogg ++ streaming, it can be controlled with an UNIX socket, filters, album/artists ++ sorting and a vi-like configuration interface. ++ . ++ It currently supports different input formats: ++ - Ogg Vorbis ++ - MP3 (with libmad) ++ - FLAC ++ - Wav ++ - Modules (with libmodplug) ++ - Musepack ++ - AAC ++ - Windows Media Audio ++ ++Package: cmus-plugin-ffmpeg ++Architecture: any ++Depends: ++ ${misc:Depends}, ++ ${shlibs:Depends}, ++ cmus (= ${binary:Version}) ++Description: lightweight ncurses audio player (FFmpeg plugin) ++ C* Music Player is a modular and very configurable ncurses-based audio player. ++ It has some interesting features like configurable colorscheme, mp3 and ogg ++ streaming, it can be controlled with an UNIX socket, filters, album/artists ++ sorting and a vi-like configuration interface. ++ . ++ This package adds FFmpeg support to C* Music Player. diff --cc debian/copyright index 0000000,0000000..01793b0 new file mode 100644 --- /dev/null +++ b/debian/copyright @@@ -1,0 -1,0 +1,38 @@@ ++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ ++Source: https://github.com/cmus/cmus ++ ++Files: * ++Copyright: 2004-2007 Timo Hirvonen ++ 2009 Gregory Petrosyan ++ 1999 Paul N. Fisher ++ 2002 Andy Lo A Foe ++ 2006 dnk ++ 2006 Chun-Yu Shei ++ 2007 Kevin Ko ++ 2007 dnk ++ 2007 Johannes Weißl ++ 2016 Nic Soudée ++License: GPL-2+ ++ ++Files: debian/* ++Copyright: 2005-2008 Julien Louis ++ 2010-2019 Ryan Kavanagh ++ 2010 Alessio Treglia ++License: GPL-2+ ++ ++License: GPL-2+ ++ This package is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ . ++ This package is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ . ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ . ++ On Debian systems, the full text of the GNU General Public License ++ version 2 can be found in `/usr/share/common-licenses/GPL-2'. diff --cc debian/docs index 0000000,0000000..93c309d new file mode 100644 --- /dev/null +++ b/debian/docs @@@ -1,0 -1,0 +1,2 @@@ ++README.md ++contrib/ diff --cc debian/examples index 0000000,0000000..5a8a7b5 new file mode 100644 --- /dev/null +++ b/debian/examples @@@ -1,0 -1,0 +1,1 @@@ ++cmus-status-display diff --cc debian/gbp.conf index 0000000,0000000..cec628c new file mode 100644 --- /dev/null +++ b/debian/gbp.conf @@@ -1,0 -1,0 +1,2 @@@ ++[DEFAULT] ++pristine-tar = True diff --cc debian/patches/0001-atomic_ld.patch index 0000000,0000000..0ecab21 new file mode 100644 --- /dev/null +++ b/debian/patches/0001-atomic_ld.patch @@@ -1,0 -1,0 +1,30 @@@ ++From: Ryan Kavanagh ++Date: Thu, 27 Jul 2023 20:59:47 +0200 ++Subject: Pass LDLIBS to the linker ++ ++Origin: Debian ++Bug-Debian: http://bugs.debian.org/935678 ++Forwarded: no ++Reviewed-by: Ryan Kavanagh ++Last-Update: 2019-09-07 ++ ++Needed to pass -latomic at the end so that we can fix a FTBFS on various ++architectures. ++Last-Update: 2019-09-07 ++--- ++ Makefile | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/Makefile b/Makefile ++index 76a4d59..720f043 100644 ++--- a/Makefile +++++ b/Makefile ++@@ -19,7 +19,7 @@ include scripts/lib.mk ++ CFLAGS += -D_FILE_OFFSET_BITS=64 ++ ++ CMUS_LIBS = $(PTHREAD_LIBS) $(NCURSES_LIBS) $(ICONV_LIBS) $(DL_LIBS) $(DISCID_LIBS) \ ++- -lm $(COMPAT_LIBS) $(LIBSYSTEMD_LIBS) +++ -lm $(COMPAT_LIBS) $(LIBSYSTEMD_LIBS) $(LDLIBS) ++ ++ command_mode.o input.o main.o ui_curses.o op/pulse.lo: .version ++ command_mode.o input.o main.o ui_curses.o op/pulse.lo: CFLAGS += -DVERSION=\"$(VERSION)\" diff --cc debian/patches/0002-fix-blhc.patch index 0000000,0000000..95dac1f new file mode 100644 --- /dev/null +++ b/debian/patches/0002-fix-blhc.patch @@@ -1,0 -1,0 +1,22 @@@ ++Description: Use hardening flags for Doc/ttman ++Author: Philippe SWARTVAGHER ++Forwarded: not-needed ++Last-Update: 2025-03-16 ++--- ++diff --git a/Makefile b/Makefile ++index 76a4d59..3860f77 100644 ++--- a/Makefile +++++ b/Makefile ++@@ -255,12 +255,6 @@ $(man7): Doc/ttman ++ %.7: %.txt ++ $(call cmd,ttman) ++ ++-Doc/ttman.o: Doc/ttman.c ++- $(call cmd,hostcc,) ++- ++-Doc/ttman: Doc/ttman.o ++- $(call cmd,hostld,) ++- ++ quiet_cmd_ttman = MAN $@ ++ cmd_ttman = Doc/ttman $< $@ ++ # }}} diff --cc debian/patches/0003-ip-ffmpeg-more-precise-seeking.patch index 0000000,0000000..e26e916 new file mode 100644 --- /dev/null +++ b/debian/patches/0003-ip-ffmpeg-more-precise-seeking.patch @@@ -1,0 -1,0 +1,229 @@@ ++From: ihy123 ++Date: Thu, 14 Aug 2025 12:44:10 +0300 ++Subject: ip/ffmpeg: more precise seeking ++ ++av_seek_frame() and avformat_seek_file() seek to nearest "keyframe". For ++codecs like, for example, ape this means that seeking will be very off ++(5 seconds or more). So what we do is: ++1. seek to nearest "keyframe" before the desired time, ++2. discard some frames to approach the desired time. ++--- ++ ip/ffmpeg.c | 154 +++++++++++++++++++++++++++++++++++++----------------------- ++ 1 file changed, 94 insertions(+), 60 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 21b9a01..ecbf005 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -44,6 +44,8 @@ struct ffmpeg_input { ++ AVPacket pkt; ++ int curr_pkt_size; ++ uint8_t *curr_pkt_buf; +++ int64_t seek_ts; +++ int64_t prev_frame_end; ++ int stream_index; ++ ++ unsigned long curr_size; ++@@ -76,6 +78,8 @@ static struct ffmpeg_input *ffmpeg_input_create(void) ++ return NULL; ++ } ++ input->curr_pkt_size = 0; +++ input->seek_ts = -1; +++ input->prev_frame_end = -1; ++ input->curr_pkt_buf = input->pkt.data; ++ return input; ++ } ++@@ -314,10 +318,7 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ #else ++ AVFrame *frame = avcodec_alloc_frame(); ++ #endif ++- int got_frame; ++ while (1) { ++- int len; ++- ++ if (input->curr_pkt_size <= 0) { ++ #if LIBAVCODEC_VERSION_MAJOR >= 56 ++ av_packet_unref(&input->pkt); ++@@ -333,78 +334,108 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ #endif ++ return 0; ++ } ++- if (input->pkt.stream_index == input->stream_index) { ++- input->curr_pkt_size = input->pkt.size; ++- input->curr_pkt_buf = input->pkt.data; ++- input->curr_size += input->pkt.size; ++- input->curr_duration += input->pkt.duration; ++- } ++- continue; ++- } ++ ++- { ++- AVPacket avpkt; ++- av_new_packet(&avpkt, input->curr_pkt_size); ++- memcpy(avpkt.data, input->curr_pkt_buf, input->curr_pkt_size); +++ if (input->pkt.stream_index != input->stream_index) +++ continue; +++ input->curr_pkt_size = input->pkt.size; +++ input->curr_pkt_buf = input->pkt.data; +++ input->curr_size += input->pkt.size; +++ input->curr_duration += input->pkt.duration; +++ ++ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++- int send_result = avcodec_send_packet(cc, &avpkt); ++- if (send_result != 0) { ++- if (send_result != AVERROR(EAGAIN)) { ++- d_print("avcodec_send_packet() returned %d\n", send_result); ++- char errstr[AV_ERROR_MAX_STRING_SIZE]; ++- if (!av_strerror(send_result, errstr, AV_ERROR_MAX_STRING_SIZE )) ++- { ++- d_print("av_strerror(): %s\n", errstr); ++- } else { ++- d_print("av_strerror(): Description for error cannot be found\n"); ++- } ++- av_packet_unref(&avpkt); ++- return -IP_ERROR_INTERNAL; +++ int send_result = avcodec_send_packet(cc, &input->pkt); +++ if (send_result != 0 && send_result != AVERROR(EAGAIN)) { +++ d_print("avcodec_send_packet() returned %d\n", send_result); +++ char errstr[AV_ERROR_MAX_STRING_SIZE]; +++ if (!av_strerror(send_result, errstr, AV_ERROR_MAX_STRING_SIZE )) +++ { +++ d_print("av_strerror(): %s\n", errstr); +++ } else { +++ d_print("av_strerror(): Description for error cannot be found\n"); ++ } ++- len = 0; ++- } else { ++- len = input->curr_pkt_size; +++ return -IP_ERROR_INTERNAL; ++ } ++- ++- int recv_result = avcodec_receive_frame(cc, frame); ++- got_frame = (recv_result == 0) ? 1 : 0; ++-#else ++- len = avcodec_decode_audio4(cc, frame, &got_frame, &avpkt); ++-#endif ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++- av_packet_unref(&avpkt); ++-#else ++- av_free_packet(&avpkt); ++ #endif ++ } +++ +++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) +++ int recv_result = avcodec_receive_frame(cc, frame); +++ if (recv_result < 0) { +++ input->curr_pkt_size = 0; +++ continue; +++ } +++#else +++ int got_frame; +++ int len = avcodec_decode_audio4(cc, frame, &got_frame, &input->pkt); ++ if (len < 0) { ++ /* this is often reached when seeking, not sure why */ ++ input->curr_pkt_size = 0; ++ continue; ++ } ++- input->curr_pkt_size -= len; ++- input->curr_pkt_buf += len; ++- if (got_frame) { ++- int res = swr_convert(swr, ++- &output->buffer, ++- frame->nb_samples, ++- (const uint8_t **)frame->extended_data, ++- frame->nb_samples); ++- if (res < 0) ++- res = 0; ++- output->buffer_pos = output->buffer; +++ if (!got_frame) +++ continue; +++#endif +++ +++ int64_t frame_ts = -1; +++ if (frame->pts) +++ frame_ts = frame->pts; +++ else if (frame->pkt_pts) +++ frame_ts = frame->pkt_pts; +++ else if (frame->pkt_dts) +++ frame_ts = frame->pkt_dts; +++ +++ const uint8_t **in = (const uint8_t **)frame->extended_data; +++ int in_count = frame->nb_samples; +++ if (input->seek_ts > 0 && (frame_ts >= 0 || input->prev_frame_end >= 0)) { +++ struct ffmpeg_private *priv = ip_data->private; +++ AVStream *st = priv->input_context->streams[priv->input->stream_index]; +++ if (frame_ts >= 0) +++ frame_ts = av_rescale_q(frame_ts, st->time_base, AV_TIME_BASE_Q); +++ else +++ frame_ts = input->prev_frame_end; +++ int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf)); +++ int64_t frame_end = frame_ts + frame_dur; +++ input->prev_frame_end = frame_end; +++ d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", input->seek_ts, frame_ts, frame_end); +++ if (frame_end <= input->seek_ts) +++ continue; +++ +++ /* skip part of this frame */ +++ int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE); +++ in_count -= skip_samples; +++ if (av_sample_fmt_is_planar(frame->format)) { +++ for (int i = 0; i < cc->channels; i++) { +++ in[i] += skip_samples * sf_get_sample_size(ip_data->sf); +++ } +++ } else { +++ *in += skip_samples * cc->channels * sf_get_sample_size(ip_data->sf); +++ } +++ +++ input->seek_ts = -1; +++ input->prev_frame_end = -1; +++ } +++ +++ int res = swr_convert(swr, +++ &output->buffer, +++ frame->nb_samples, +++ in, +++ in_count); +++ if (res < 0) +++ res = 0; +++ +++ output->buffer_pos = output->buffer; ++ #if LIBAVCODEC_VERSION_MAJOR >= 60 ++- output->buffer_used_len = res * cc->ch_layout.nb_channels * sf_get_sample_size(ip_data->sf); +++ output->buffer_used_len = res * cc->ch_layout.nb_channels * sf_get_sample_size(ip_data->sf); ++ #else ++- output->buffer_used_len = res * cc->channels * sf_get_sample_size(ip_data->sf); +++ output->buffer_used_len = res * cc->channels * sf_get_sample_size(ip_data->sf); ++ #endif +++ ++ #if LIBAVCODEC_VERSION_MAJOR >= 56 ++- av_frame_free(&frame); +++ av_frame_free(&frame); ++ #else ++- avcodec_free_frame(&frame); +++ avcodec_free_frame(&frame); ++ #endif ++- return output->buffer_used_len; ++- } +++ return output->buffer_used_len; ++ } ++ /* This should never get here. */ ++ return -IP_ERROR_INTERNAL; ++@@ -437,13 +468,16 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ AVStream *st = priv->input_context->streams[priv->input->stream_index]; ++ int ret; ++ ++- int64_t pts = av_rescale_q(offset * AV_TIME_BASE, AV_TIME_BASE_Q, st->time_base); +++ priv->input->seek_ts = offset * AV_TIME_BASE; +++ priv->input->prev_frame_end = -1; +++ int64_t ts = av_rescale(offset, st->time_base.den, st->time_base.num); ++ ++ avcodec_flush_buffers(priv->codec_context); ++ /* Force reading a new packet in next ffmpeg_fill_buffer(). */ ++ priv->input->curr_pkt_size = 0; ++ ++- ret = av_seek_frame(priv->input_context, priv->input->stream_index, pts, 0); +++ ret = avformat_seek_file(priv->input_context, +++ priv->input->stream_index, 0, ts, ts, 0); ++ ++ if (ret < 0) { ++ return -IP_ERROR_FUNCTION_NOT_SUPPORTED; diff --cc debian/patches/0004-ip-ffmpeg-skip-samples-only-when-needed.patch index 0000000,0000000..1e0a634 new file mode 100644 --- /dev/null +++ b/debian/patches/0004-ip-ffmpeg-skip-samples-only-when-needed.patch @@@ -1,0 -1,0 +1,53 @@@ ++From: ihy123 ++Date: Fri, 15 Aug 2025 21:42:19 +0300 ++Subject: ip/ffmpeg: skip samples only when needed ++ ++--- ++ ip/ffmpeg.c | 32 ++++++++++++++++++-------------- ++ 1 file changed, 18 insertions(+), 14 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index ecbf005..5f5a4f3 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -393,22 +393,26 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ frame_ts = av_rescale_q(frame_ts, st->time_base, AV_TIME_BASE_Q); ++ else ++ frame_ts = input->prev_frame_end; ++- int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf)); ++- int64_t frame_end = frame_ts + frame_dur; ++- input->prev_frame_end = frame_end; ++- d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", input->seek_ts, frame_ts, frame_end); ++- if (frame_end <= input->seek_ts) ++- continue; ++ ++- /* skip part of this frame */ ++- int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE); ++- in_count -= skip_samples; ++- if (av_sample_fmt_is_planar(frame->format)) { ++- for (int i = 0; i < cc->channels; i++) { ++- in[i] += skip_samples * sf_get_sample_size(ip_data->sf); +++ if (frame_ts < input->seek_ts) { +++ int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf)); +++ int64_t frame_end = frame_ts + frame_dur; +++ input->prev_frame_end = frame_end; +++ d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", input->seek_ts, frame_ts, frame_end); +++ if (frame_end <= input->seek_ts) +++ continue; +++ +++ /* skip part of this frame */ +++ int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE); +++ in_count -= skip_samples; +++ if (av_sample_fmt_is_planar(frame->format)) { +++ for (int i = 0; i < cc->channels; i++) { +++ in[i] += skip_samples * sf_get_sample_size(ip_data->sf); +++ } +++ } else { +++ *in += skip_samples * cc->channels * sf_get_sample_size(ip_data->sf); ++ } ++- } else { ++- *in += skip_samples * cc->channels * sf_get_sample_size(ip_data->sf); +++ d_print("skipping %ld samples\n", skip_samples); ++ } ++ ++ input->seek_ts = -1; diff --cc debian/patches/0005-ip-ffmpeg-remove-excessive-version-checks.patch index 0000000,0000000..20aebf0 new file mode 100644 --- /dev/null +++ b/debian/patches/0005-ip-ffmpeg-remove-excessive-version-checks.patch @@@ -1,0 -1,0 +1,342 @@@ ++From: ihy123 ++Date: Sat, 16 Aug 2025 02:43:55 +0300 ++Subject: ip/ffmpeg: remove excessive version checks ++ ++ffmpeg download page states that v4.0.6 has ++- libavutil 56.14.100 ++- libavcodec 58.18.100 ++- libavformat 58.12.100 ++(https://ffmpeg.org/olddownload.html) ++ ++After removing all checks for versions lower than these, the plugin ++still compiles with v3.3.9 headers. ++ ++After all, why be better with compatibility than developers themselves? ++--- ++ ip/ffmpeg.c | 109 +++++++++++++----------------------------------------------- ++ 1 file changed, 23 insertions(+), 86 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 5f5a4f3..f6a11f4 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -25,7 +25,6 @@ ++ #include "../config/ffmpeg.h" ++ #endif ++ ++-#include ++ #include ++ #include ++ #include ++@@ -43,7 +42,6 @@ ++ struct ffmpeg_input { ++ AVPacket pkt; ++ int curr_pkt_size; ++- uint8_t *curr_pkt_buf; ++ int64_t seek_ts; ++ int64_t prev_frame_end; ++ int stream_index; ++@@ -80,17 +78,12 @@ static struct ffmpeg_input *ffmpeg_input_create(void) ++ input->curr_pkt_size = 0; ++ input->seek_ts = -1; ++ input->prev_frame_end = -1; ++- input->curr_pkt_buf = input->pkt.data; ++ return input; ++ } ++ ++ static void ffmpeg_input_free(struct ffmpeg_input *input) ++ { ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++ av_packet_unref(&input->pkt); ++-#else ++- av_free_packet(&input->pkt); ++-#endif ++ free(input); ++ } ++ ++@@ -132,7 +125,7 @@ static void ffmpeg_init(void) ++ ++ av_log_set_level(AV_LOG_QUIET); ++ ++-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100) +++#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) ++ /* We could register decoders explicitly to save memory, but we have to ++ * be careful about compatibility. */ ++ av_register_all(); ++@@ -149,9 +142,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ AVCodec const *codec; ++ AVCodecContext *cc = NULL; ++ AVFormatContext *ic = NULL; ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ AVCodecParameters *cp = NULL; ++-#endif ++ SwrContext *swr = NULL; ++ ++ ffmpeg_init(); ++@@ -171,20 +162,11 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ } ++ ++ for (i = 0; i < ic->nb_streams; i++) { ++- ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ cp = ic->streams[i]->codecpar; ++ if (cp->codec_type == AVMEDIA_TYPE_AUDIO) { ++ stream_index = i; ++ break; ++ } ++-#else ++- cc = ic->streams[i]->codec; ++- if (cc->codec_type == AVMEDIA_TYPE_AUDIO) { ++- stream_index = i; ++- break; ++- } ++-#endif ++ } ++ ++ if (stream_index == -1) { ++@@ -193,13 +175,9 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ break; ++ } ++ ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ codec = avcodec_find_decoder(cp->codec_id); ++ cc = avcodec_alloc_context3(codec); ++ avcodec_parameters_to_context(cc, cp); ++-#else ++- codec = avcodec_find_decoder(cc->codec_id); ++-#endif ++ if (!codec) { ++ d_print("codec not found: %d, %s\n", cc->codec_id, avcodec_get_name(cc->codec_id)); ++ err = -IP_ERROR_UNSUPPORTED_FILE_TYPE; ++@@ -217,9 +195,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ ++ if (err < 0) { ++ /* Clean up. cc is never opened at this point. (See above assumption.) */ ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ avcodec_free_context(&cc); ++-#endif ++ avformat_close_input(&ic); ++ return err; ++ } ++@@ -231,9 +207,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ priv->input = ffmpeg_input_create(); ++ if (priv->input == NULL) { ++ avcodec_close(cc); ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ avcodec_free_context(&cc); ++-#endif ++ avformat_close_input(&ic); ++ free(priv); ++ return -IP_ERROR_INTERNAL; ++@@ -244,7 +218,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ /* Prepare for resampling. */ ++ out_sample_rate = min_u(cc->sample_rate, 384000); ++ swr = swr_alloc(); ++-#if LIBAVCODEC_VERSION_MAJOR >= 60 +++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) ++ if (cc->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) ++ av_channel_layout_default(&cc->ch_layout, cc->ch_layout.nb_channels); ++ av_opt_set_chlayout(swr, "in_chlayout", &cc->ch_layout, 0); ++@@ -259,7 +233,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ priv->swr = swr; ++ ++ ip_data->private = priv; ++-#if LIBAVCODEC_VERSION_MAJOR >= 60 +++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) ++ ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->ch_layout.nb_channels); ++ #else ++ ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->channels); ++@@ -281,10 +255,12 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ } ++ swr_init(swr); ++ ip_data->sf |= sf_host_endian(); ++-#if LIBAVCODEC_VERSION_MAJOR >= 60 ++- channel_map_init_waveex(cc->ch_layout.nb_channels, cc->ch_layout.u.mask, ip_data->channel_map); +++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) +++ channel_map_init_waveex(cc->ch_layout.nb_channels, +++ cc->ch_layout.u.mask, ip_data->channel_map); ++ #else ++- channel_map_init_waveex(cc->channels, cc->channel_layout, ip_data->channel_map); +++ channel_map_init_waveex(cc->channels, +++ cc->channel_layout, ip_data->channel_map); ++ #endif ++ return 0; ++ } ++@@ -294,9 +270,7 @@ static int ffmpeg_close(struct input_plugin_data *ip_data) ++ struct ffmpeg_private *priv = ip_data->private; ++ ++ avcodec_close(priv->codec_context); ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ avcodec_free_context(&priv->codec_context); ++-#endif ++ avformat_close_input(&priv->input_context); ++ swr_free(&priv->swr); ++ ffmpeg_input_free(priv->input); ++@@ -310,39 +284,27 @@ static int ffmpeg_close(struct input_plugin_data *ip_data) ++ * This returns the number of bytes added to the buffer. ++ * It returns < 0 on error. 0 on EOF. ++ */ ++-static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext *ic, AVCodecContext *cc, ++- struct ffmpeg_input *input, struct ffmpeg_output *output, SwrContext *swr) +++static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, +++ AVFormatContext *ic, AVCodecContext *cc, +++ struct ffmpeg_input *input, struct ffmpeg_output *output, +++ SwrContext *swr) ++ { ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++ AVFrame *frame = av_frame_alloc(); ++-#else ++- AVFrame *frame = avcodec_alloc_frame(); ++-#endif ++ while (1) { ++ if (input->curr_pkt_size <= 0) { ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++ av_packet_unref(&input->pkt); ++-#else ++- av_free_packet(&input->pkt); ++-#endif ++ if (av_read_frame(ic, &input->pkt) < 0) { ++ /* Force EOF once we can read no longer. */ ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++ av_frame_free(&frame); ++-#else ++- avcodec_free_frame(&frame); ++-#endif ++ return 0; ++ } ++ ++ if (input->pkt.stream_index != input->stream_index) ++ continue; ++ input->curr_pkt_size = input->pkt.size; ++- input->curr_pkt_buf = input->pkt.data; ++ input->curr_size += input->pkt.size; ++ input->curr_duration += input->pkt.duration; ++ ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ int send_result = avcodec_send_packet(cc, &input->pkt); ++ if (send_result != 0 && send_result != AVERROR(EAGAIN)) { ++ d_print("avcodec_send_packet() returned %d\n", send_result); ++@@ -355,32 +317,17 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ } ++ return -IP_ERROR_INTERNAL; ++ } ++-#endif ++ } ++ ++-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) ++ int recv_result = avcodec_receive_frame(cc, frame); ++ if (recv_result < 0) { ++ input->curr_pkt_size = 0; ++ continue; ++ } ++-#else ++- int got_frame; ++- int len = avcodec_decode_audio4(cc, frame, &got_frame, &input->pkt); ++- if (len < 0) { ++- /* this is often reached when seeking, not sure why */ ++- input->curr_pkt_size = 0; ++- continue; ++- } ++- if (!got_frame) ++- continue; ++-#endif ++ ++ int64_t frame_ts = -1; ++ if (frame->pts) ++ frame_ts = frame->pts; ++- else if (frame->pkt_pts) ++- frame_ts = frame->pkt_pts; ++ else if (frame->pkt_dts) ++ frame_ts = frame->pkt_dts; ++ ++@@ -395,7 +342,7 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ frame_ts = input->prev_frame_end; ++ ++ if (frame_ts < input->seek_ts) { ++- int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf)); +++ int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, frame->sample_rate); ++ int64_t frame_end = frame_ts + frame_dur; ++ input->prev_frame_end = frame_end; ++ d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", input->seek_ts, frame_ts, frame_end); ++@@ -403,14 +350,14 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ continue; ++ ++ /* skip part of this frame */ ++- int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE); +++ int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, frame->sample_rate, AV_TIME_BASE); ++ in_count -= skip_samples; ++ if (av_sample_fmt_is_planar(frame->format)) { ++- for (int i = 0; i < cc->channels; i++) { +++ for (int i = 0; i < sf_get_channels(ip_data->sf); i++) { ++ in[i] += skip_samples * sf_get_sample_size(ip_data->sf); ++ } ++ } else { ++- *in += skip_samples * cc->channels * sf_get_sample_size(ip_data->sf); +++ *in += skip_samples * sf_get_frame_size(ip_data->sf); ++ } ++ d_print("skipping %ld samples\n", skip_samples); ++ } ++@@ -428,17 +375,9 @@ static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, AVFormatContext ++ res = 0; ++ ++ output->buffer_pos = output->buffer; ++-#if LIBAVCODEC_VERSION_MAJOR >= 60 ++- output->buffer_used_len = res * cc->ch_layout.nb_channels * sf_get_sample_size(ip_data->sf); ++-#else ++- output->buffer_used_len = res * cc->channels * sf_get_sample_size(ip_data->sf); ++-#endif +++ output->buffer_used_len = res * sf_get_frame_size(ip_data->sf); ++ ++-#if LIBAVCODEC_VERSION_MAJOR >= 56 ++ av_frame_free(&frame); ++-#else ++- avcodec_free_frame(&frame); ++-#endif ++ return output->buffer_used_len; ++ } ++ /* This should never get here. */ ++@@ -453,11 +392,11 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun ++ int out_size; ++ ++ if (output->buffer_used_len == 0) { ++- rc = ffmpeg_fill_buffer(ip_data, priv->input_context, priv->codec_context, +++ rc = ffmpeg_fill_buffer(ip_data, +++ priv->input_context, priv->codec_context, ++ priv->input, priv->output, priv->swr); ++- if (rc <= 0) { +++ if (rc <= 0) ++ return rc; ++- } ++ } ++ out_size = min_i(output->buffer_used_len, count); ++ memcpy(buffer, output->buffer_pos, out_size); ++@@ -477,6 +416,7 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ int64_t ts = av_rescale(offset, st->time_base.den, st->time_base.num); ++ ++ avcodec_flush_buffers(priv->codec_context); +++ /* TODO: also flush swresample buffers */ ++ /* Force reading a new packet in next ffmpeg_fill_buffer(). */ ++ priv->input->curr_pkt_size = 0; ++ ++@@ -501,7 +441,8 @@ static void ffmpeg_read_metadata(struct growing_keyvals *c, AVDictionary *metada ++ } ++ } ++ ++-static int ffmpeg_read_comments(struct input_plugin_data *ip_data, struct keyval **comments) +++static int ffmpeg_read_comments(struct input_plugin_data *ip_data, +++ struct keyval **comments) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++ AVFormatContext *ic = priv->input_context; ++@@ -538,11 +479,7 @@ static long ffmpeg_current_bitrate(struct input_plugin_data *ip_data) ++ AVStream *st = priv->input_context->streams[priv->input->stream_index]; ++ long bitrate = -1; ++ /* ape codec returns silly numbers */ ++-#if LIBAVCODEC_VERSION_MAJOR >= 55 ++ if (priv->codec->id == AV_CODEC_ID_APE) ++-#else ++- if (priv->codec->id == CODEC_ID_APE) ++-#endif ++ return -1; ++ if (priv->input->curr_duration > 0) { ++ double seconds = priv->input->curr_duration * av_q2d(st->time_base); diff --cc debian/patches/0006-ip-ffmpeg-major-refactor.patch index 0000000,0000000..507c654 new file mode 100644 --- /dev/null +++ b/debian/patches/0006-ip-ffmpeg-major-refactor.patch @@@ -1,0 -1,0 +1,777 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 04:05:36 +0300 ++Subject: ip/ffmpeg: major refactor ++ ++--- ++ ip/ffmpeg.c | 643 +++++++++++++++++++++++++++++++----------------------------- ++ 1 file changed, 330 insertions(+), 313 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index f6a11f4..42f630e 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -35,84 +35,32 @@ ++ #include ++ #endif ++ ++-#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE ++-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 ++-#endif +++struct ffmpeg_private { +++ AVCodecContext *codec_ctx; +++ AVFormatContext *format_ctx; +++ AVCodec const *codec; +++ SwrContext *swr; +++ int stream_index; ++ ++-struct ffmpeg_input { ++- AVPacket pkt; ++- int curr_pkt_size; +++ AVPacket *pkt; +++ AVFrame *frame; ++ int64_t seek_ts; ++ int64_t prev_frame_end; ++- int stream_index; ++ +++ /* A buffer to hold swr_convert()-ed samples */ +++ AVFrame *swr_frame; +++ int swr_frame_start; +++ +++ /* Bitrate estimation */ ++ unsigned long curr_size; ++ unsigned long curr_duration; ++ }; ++ ++-struct ffmpeg_output { ++- uint8_t *buffer; ++- uint8_t *buffer_malloc; ++- uint8_t *buffer_pos; /* current buffer position */ ++- int buffer_used_len; ++-}; ++- ++-struct ffmpeg_private { ++- AVCodecContext *codec_context; ++- AVFormatContext *input_context; ++- AVCodec const *codec; ++- SwrContext *swr; ++- ++- struct ffmpeg_input *input; ++- struct ffmpeg_output *output; ++-}; ++- ++-static struct ffmpeg_input *ffmpeg_input_create(void) ++-{ ++- struct ffmpeg_input *input = xnew(struct ffmpeg_input, 1); ++- ++- if (av_new_packet(&input->pkt, 0) != 0) { ++- free(input); ++- return NULL; ++- } ++- input->curr_pkt_size = 0; ++- input->seek_ts = -1; ++- input->prev_frame_end = -1; ++- return input; ++-} ++- ++-static void ffmpeg_input_free(struct ffmpeg_input *input) ++-{ ++- av_packet_unref(&input->pkt); ++- free(input); ++-} ++- ++-static struct ffmpeg_output *ffmpeg_output_create(void) ++-{ ++- struct ffmpeg_output *output = xnew(struct ffmpeg_output, 1); ++- ++- output->buffer_malloc = xnew(uint8_t, AVCODEC_MAX_AUDIO_FRAME_SIZE + 15); ++- output->buffer = output->buffer_malloc; ++- /* align to 16 bytes so avcodec can SSE/Altivec/etc */ ++- while ((intptr_t) output->buffer % 16) ++- output->buffer += 1; ++- output->buffer_pos = output->buffer; ++- output->buffer_used_len = 0; ++- return output; ++-} ++- ++-static void ffmpeg_output_free(struct ffmpeg_output *output) ++-{ ++- free(output->buffer_malloc); ++- output->buffer_malloc = NULL; ++- output->buffer = NULL; ++- free(output); ++-} ++- ++-static inline void ffmpeg_buffer_flush(struct ffmpeg_output *output) +++static const char *ffmpeg_errmsg(int err) ++ { ++- output->buffer_pos = output->buffer; ++- output->buffer_used_len = 0; +++ static char errstr[AV_ERROR_MAX_STRING_SIZE]; +++ av_strerror(err, errstr, AV_ERROR_MAX_STRING_SIZE); +++ return errstr; ++ } ++ ++ static void ffmpeg_init(void) ++@@ -132,303 +80,372 @@ static void ffmpeg_init(void) ++ #endif ++ } ++ ++-static int ffmpeg_open(struct input_plugin_data *ip_data) +++static int ffmpeg_open_input(struct input_plugin_data *ip_data, +++ struct ffmpeg_private *priv) ++ { ++- struct ffmpeg_private *priv; ++- int err = 0; ++- int i; ++- int stream_index = -1; ++- int out_sample_rate; ++- AVCodec const *codec; ++- AVCodecContext *cc = NULL; ++ AVFormatContext *ic = NULL; +++ AVCodecContext *cc = NULL; ++ AVCodecParameters *cp = NULL; ++- SwrContext *swr = NULL; ++- ++- ffmpeg_init(); +++ AVCodec const *codec = NULL; +++ int stream_index = -1; ++ ++- err = avformat_open_input(&ic, ip_data->filename, NULL, NULL); ++- if (err < 0) { ++- d_print("av_open failed: %d\n", err); ++- return -IP_ERROR_FILE_FORMAT; +++ int err; +++ int res = avformat_open_input(&ic, ip_data->filename, NULL, NULL); +++ if (res < 0) { +++ err = -IP_ERROR_FILE_FORMAT; +++ goto err; ++ } ++ ++- do { ++- err = avformat_find_stream_info(ic, NULL); ++- if (err < 0) { ++- d_print("unable to find stream info: %d\n", err); ++- err = -IP_ERROR_FILE_FORMAT; ++- break; ++- } ++- ++- for (i = 0; i < ic->nb_streams; i++) { ++- cp = ic->streams[i]->codecpar; ++- if (cp->codec_type == AVMEDIA_TYPE_AUDIO) { ++- stream_index = i; ++- break; ++- } ++- } ++- ++- if (stream_index == -1) { ++- d_print("could not find audio stream\n"); ++- err = -IP_ERROR_FILE_FORMAT; ++- break; ++- } ++- ++- codec = avcodec_find_decoder(cp->codec_id); ++- cc = avcodec_alloc_context3(codec); ++- avcodec_parameters_to_context(cc, cp); ++- if (!codec) { ++- d_print("codec not found: %d, %s\n", cc->codec_id, avcodec_get_name(cc->codec_id)); ++- err = -IP_ERROR_UNSUPPORTED_FILE_TYPE; ++- break; ++- } +++ res = avformat_find_stream_info(ic, NULL); +++ if (res < 0) { +++ d_print("unable to find stream info\n"); +++ err = -IP_ERROR_FILE_FORMAT; +++ goto err; +++ } ++ ++- if (avcodec_open2(cc, codec, NULL) < 0) { ++- d_print("could not open codec: %d, %s\n", cc->codec_id, avcodec_get_name(cc->codec_id)); ++- err = -IP_ERROR_UNSUPPORTED_FILE_TYPE; +++ for (int i = 0; i < ic->nb_streams; i++) { +++ cp = ic->streams[i]->codecpar; +++ if (cp->codec_type == AVMEDIA_TYPE_AUDIO) { +++ stream_index = i; ++ break; ++ } +++ } ++ ++- /* We assume below that no more errors follow. */ ++- } while (0); +++ if (stream_index == -1) { +++ d_print("could not find audio stream\n"); +++ err = -IP_ERROR_FILE_FORMAT; +++ goto err_silent; +++ } ++ ++- if (err < 0) { ++- /* Clean up. cc is never opened at this point. (See above assumption.) */ ++- avcodec_free_context(&cc); ++- avformat_close_input(&ic); ++- return err; +++ codec = avcodec_find_decoder(cp->codec_id); +++ if (!codec) { +++ d_print("codec (id: %d, name: %s) not found\n", +++ cc->codec_id, avcodec_get_name(cc->codec_id)); +++ err = -IP_ERROR_UNSUPPORTED_FILE_TYPE; +++ goto err_silent; +++ } +++ cc = avcodec_alloc_context3(codec); +++ avcodec_parameters_to_context(cc, cp); +++ +++ res = avcodec_open2(cc, codec, NULL); +++ if (res < 0) { +++ d_print("could not open codec (id: %d, name: %s)\n", +++ cc->codec_id, avcodec_get_name(cc->codec_id)); +++ err = -IP_ERROR_UNSUPPORTED_FILE_TYPE; +++ goto err; ++ } ++ ++- priv = xnew(struct ffmpeg_private, 1); ++- priv->codec_context = cc; ++- priv->input_context = ic; +++ priv->format_ctx = ic; +++ priv->codec_ctx = cc; ++ priv->codec = codec; ++- priv->input = ffmpeg_input_create(); ++- if (priv->input == NULL) { ++- avcodec_close(cc); ++- avcodec_free_context(&cc); ++- avformat_close_input(&ic); ++- free(priv); ++- return -IP_ERROR_INTERNAL; +++ priv->stream_index = stream_index; +++ return 0; +++err: +++ d_print("%s\n", ffmpeg_errmsg(res)); +++err_silent: +++ avcodec_free_context(&cc); +++ avformat_close_input(&ic); +++ return err; +++} +++ +++static void ffmpeg_set_sf_and_swr_opts(SwrContext *swr, AVCodecContext *cc, +++ sample_format_t *sf_out, enum AVSampleFormat *out_sample_fmt) +++{ +++ int out_sample_rate = min_u(cc->sample_rate, 384000); +++ sample_format_t sf = sf_rate(out_sample_rate) | sf_host_endian(); +++ av_opt_set_int(swr, "in_sample_rate", cc->sample_rate, 0); +++ av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); +++ +++ *out_sample_fmt = cc->sample_fmt; +++ switch (*out_sample_fmt) { +++ case AV_SAMPLE_FMT_U8: +++ sf |= sf_bits(8) | sf_signed(0); +++ break; +++ case AV_SAMPLE_FMT_S32: +++ sf |= sf_bits(32) | sf_signed(1); +++ break; +++ default: +++ sf |= sf_bits(16) | sf_signed(1); +++ *out_sample_fmt = AV_SAMPLE_FMT_S16; ++ } ++- priv->input->stream_index = stream_index; ++- priv->output = ffmpeg_output_create(); +++ av_opt_set_sample_fmt(swr, "in_sample_fmt", cc->sample_fmt, 0); +++ av_opt_set_sample_fmt(swr, "out_sample_fmt", *out_sample_fmt, 0); ++ ++- /* Prepare for resampling. */ ++- out_sample_rate = min_u(cc->sample_rate, 384000); ++- swr = swr_alloc(); ++ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) +++ sf |= sf_channels(cc->ch_layout.nb_channels); +++ ++ if (cc->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) ++ av_channel_layout_default(&cc->ch_layout, cc->ch_layout.nb_channels); ++- av_opt_set_chlayout(swr, "in_chlayout", &cc->ch_layout, 0); ++- av_opt_set_chlayout(swr, "out_chlayout", &cc->ch_layout, 0); +++ av_opt_set_chlayout(swr, "in_chlayout", &cc->ch_layout, 0); +++ av_opt_set_chlayout(swr, "out_chlayout", &cc->ch_layout, 0); ++ #else ++- av_opt_set_int(swr, "in_channel_layout", av_get_default_channel_layout(cc->channels), 0); ++- av_opt_set_int(swr, "out_channel_layout", av_get_default_channel_layout(cc->channels), 0); +++ sf |= sf_channels(cc->channels); +++ +++ av_opt_set_int(swr, "in_channel_layout", +++ av_get_default_channel_layout(cc->channels), 0); +++ av_opt_set_int(swr, "out_channel_layout", +++ av_get_default_channel_layout(cc->channels), 0); ++ #endif ++- av_opt_set_int(swr, "in_sample_rate", cc->sample_rate, 0); ++- av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); ++- av_opt_set_sample_fmt(swr, "in_sample_fmt", cc->sample_fmt, 0); ++- priv->swr = swr; ++ ++- ip_data->private = priv; +++ *sf_out = sf; +++} +++ +++static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv, +++ sample_format_t sf, enum AVSampleFormat out_sample_fmt) +++{ +++ AVCodecContext *cc = priv->codec_ctx; +++ AVFrame *frame = av_frame_alloc(); +++ ++ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) ++- ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->ch_layout.nb_channels); +++ av_channel_layout_copy(&frame->ch_layout, &cc->ch_layout); ++ #else ++- ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->channels); +++ frame->channel_layout = av_get_default_channel_layout(cc->channels); ++ #endif ++- switch (cc->sample_fmt) { ++- case AV_SAMPLE_FMT_U8: ++- ip_data->sf |= sf_bits(8) | sf_signed(0); ++- av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_U8, 0); ++- break; ++- case AV_SAMPLE_FMT_S32: ++- ip_data->sf |= sf_bits(32) | sf_signed(1); ++- av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S32, 0); ++- break; ++- /* AV_SAMPLE_FMT_S16 */ ++- default: ++- ip_data->sf |= sf_bits(16) | sf_signed(1); ++- av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); ++- break; +++ +++ frame->sample_rate = sf_get_rate(sf); +++ frame->format = out_sample_fmt; +++ +++ /* NOTE: 10 sec is probably too much, but the amount of space +++ * needed for swr_convert() is unpredictable */ +++ frame->nb_samples = 10 * sf_get_rate(sf); +++ int res = av_frame_get_buffer(frame, 0); +++ if (res < 0) { +++ d_print("av_frame_get_buffer(): %s\n", ffmpeg_errmsg(res)); +++ return -IP_ERROR_INTERNAL; ++ } ++- swr_init(swr); ++- ip_data->sf |= sf_host_endian(); +++ frame->nb_samples = 0; +++ +++ priv->swr_frame = frame; +++ return 0; +++} +++ +++static void ffmpeg_free(struct ffmpeg_private *priv) +++{ +++ avcodec_close(priv->codec_ctx); +++ avcodec_free_context(&priv->codec_ctx); +++ avformat_close_input(&priv->format_ctx); +++ +++ swr_free(&priv->swr); +++ +++ av_frame_free(&priv->frame); +++ av_packet_free(&priv->pkt); +++ av_frame_free(&priv->swr_frame); +++} +++ +++static int ffmpeg_open(struct input_plugin_data *ip_data) +++{ +++ struct ffmpeg_private priv; +++ enum AVSampleFormat out_sample_fmt; +++ memset(&priv, 0, sizeof(struct ffmpeg_private)); +++ +++ ffmpeg_init(); +++ +++ int err = ffmpeg_open_input(ip_data, &priv); +++ if (err < 0) +++ return err; +++ +++ priv.pkt = av_packet_alloc(); +++ priv.frame = av_frame_alloc(); +++ priv.seek_ts = -1; +++ priv.prev_frame_end = -1; +++ +++ priv.swr = swr_alloc(); +++ ffmpeg_set_sf_and_swr_opts(priv.swr, priv.codec_ctx, +++ &ip_data->sf, &out_sample_fmt); +++ swr_init(priv.swr); +++ +++ err = ffmpeg_init_swr_frame(&priv, ip_data->sf, out_sample_fmt); +++ if (err < 0) { +++ ffmpeg_free(&priv); +++ return err; +++ } +++ ++ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) ++- channel_map_init_waveex(cc->ch_layout.nb_channels, ++- cc->ch_layout.u.mask, ip_data->channel_map); +++ channel_map_init_waveex(priv.codec_ctx->ch_layout.nb_channels, +++ priv.codec_ctx->ch_layout.u.mask, ip_data->channel_map); ++ #else ++- channel_map_init_waveex(cc->channels, ++- cc->channel_layout, ip_data->channel_map); +++ channel_map_init_waveex(priv.codec_ctx->channels, +++ priv.codec_ctx->channel_layout, ip_data->channel_map); ++ #endif +++ +++ ip_data->private = xnew(struct ffmpeg_private, 1); +++ memcpy(ip_data->private, &priv, sizeof(struct ffmpeg_private)); ++ return 0; ++ } ++ ++ static int ffmpeg_close(struct input_plugin_data *ip_data) ++ { ++- struct ffmpeg_private *priv = ip_data->private; ++- ++- avcodec_close(priv->codec_context); ++- avcodec_free_context(&priv->codec_context); ++- avformat_close_input(&priv->input_context); ++- swr_free(&priv->swr); ++- ffmpeg_input_free(priv->input); ++- ffmpeg_output_free(priv->output); ++- free(priv); +++ ffmpeg_free(ip_data->private); +++ free(ip_data->private); ++ ip_data->private = NULL; ++ return 0; ++ } ++ ++ /* ++- * This returns the number of bytes added to the buffer. ++- * It returns < 0 on error. 0 on EOF. +++ * return: +++ * 0 - retry +++ * >0 - ok ++ */ ++-static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data, ++- AVFormatContext *ic, AVCodecContext *cc, ++- struct ffmpeg_input *input, struct ffmpeg_output *output, ++- SwrContext *swr) +++static int ffmpeg_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts) ++ { ++- AVFrame *frame = av_frame_alloc(); ++- while (1) { ++- if (input->curr_pkt_size <= 0) { ++- av_packet_unref(&input->pkt); ++- if (av_read_frame(ic, &input->pkt) < 0) { ++- /* Force EOF once we can read no longer. */ ++- av_frame_free(&frame); ++- return 0; ++- } ++- ++- if (input->pkt.stream_index != input->stream_index) ++- continue; ++- input->curr_pkt_size = input->pkt.size; ++- input->curr_size += input->pkt.size; ++- input->curr_duration += input->pkt.duration; ++- ++- int send_result = avcodec_send_packet(cc, &input->pkt); ++- if (send_result != 0 && send_result != AVERROR(EAGAIN)) { ++- d_print("avcodec_send_packet() returned %d\n", send_result); ++- char errstr[AV_ERROR_MAX_STRING_SIZE]; ++- if (!av_strerror(send_result, errstr, AV_ERROR_MAX_STRING_SIZE )) ++- { ++- d_print("av_strerror(): %s\n", errstr); ++- } else { ++- d_print("av_strerror(): Description for error cannot be found\n"); ++- } ++- return -IP_ERROR_INTERNAL; ++- } ++- } +++ if (frame_ts >= 0) { +++ AVStream *s = priv->format_ctx->streams[priv->stream_index]; +++ frame_ts = av_rescale_q(frame_ts, s->time_base, AV_TIME_BASE_Q); +++ } else { +++ frame_ts = priv->prev_frame_end; +++ } ++ ++- int recv_result = avcodec_receive_frame(cc, frame); ++- if (recv_result < 0) { ++- input->curr_pkt_size = 0; ++- continue; ++- } +++ if (frame_ts >= priv->seek_ts) +++ return 1; ++ ++- int64_t frame_ts = -1; ++- if (frame->pts) ++- frame_ts = frame->pts; ++- else if (frame->pkt_dts) ++- frame_ts = frame->pkt_dts; ++- ++- const uint8_t **in = (const uint8_t **)frame->extended_data; ++- int in_count = frame->nb_samples; ++- if (input->seek_ts > 0 && (frame_ts >= 0 || input->prev_frame_end >= 0)) { ++- struct ffmpeg_private *priv = ip_data->private; ++- AVStream *st = priv->input_context->streams[priv->input->stream_index]; ++- if (frame_ts >= 0) ++- frame_ts = av_rescale_q(frame_ts, st->time_base, AV_TIME_BASE_Q); ++- else ++- frame_ts = input->prev_frame_end; ++- ++- if (frame_ts < input->seek_ts) { ++- int64_t frame_dur = av_rescale(frame->nb_samples, AV_TIME_BASE, frame->sample_rate); ++- int64_t frame_end = frame_ts + frame_dur; ++- input->prev_frame_end = frame_end; ++- d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", input->seek_ts, frame_ts, frame_end); ++- if (frame_end <= input->seek_ts) ++- continue; ++- ++- /* skip part of this frame */ ++- int64_t skip_samples = av_rescale(input->seek_ts - frame_ts, frame->sample_rate, AV_TIME_BASE); ++- in_count -= skip_samples; ++- if (av_sample_fmt_is_planar(frame->format)) { ++- for (int i = 0; i < sf_get_channels(ip_data->sf); i++) { ++- in[i] += skip_samples * sf_get_sample_size(ip_data->sf); ++- } ++- } else { ++- *in += skip_samples * sf_get_frame_size(ip_data->sf); ++- } ++- d_print("skipping %ld samples\n", skip_samples); ++- } ++- ++- input->seek_ts = -1; ++- input->prev_frame_end = -1; ++- } +++ int64_t frame_dur = av_rescale(priv->frame->nb_samples, +++ AV_TIME_BASE, priv->frame->sample_rate); +++ int64_t frame_end = frame_ts + frame_dur; +++ priv->prev_frame_end = frame_end; +++ +++ d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", +++ priv->seek_ts, frame_ts, frame_end); +++ +++ if (frame_end <= priv->seek_ts) +++ return 0; +++ +++ int64_t skip_samples = av_rescale(priv->seek_ts - frame_ts, +++ priv->frame->sample_rate, AV_TIME_BASE); +++ priv->frame->nb_samples -= skip_samples; +++ +++ int bps = av_get_bytes_per_sample(priv->frame->format); +++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) +++ int channels = priv->codec_ctx->ch_layout.nb_channels; +++#else +++ int channels = priv->codec_ctx->channels; +++#endif +++ +++ /* Just modify frame's data pointer because it's throw-away */ +++ if (av_sample_fmt_is_planar(priv->frame->format)) { +++ for (int i = 0; i < channels; i++) +++ priv->frame->extended_data[i] += skip_samples * bps; +++ } else { +++ priv->frame->extended_data[0] += skip_samples * channels * bps; +++ } +++ d_print("skipping %ld samples\n", skip_samples); +++ return 1; +++} ++ ++- int res = swr_convert(swr, ++- &output->buffer, ++- frame->nb_samples, ++- in, ++- in_count); +++/* +++ * return: +++ * <0 - error +++ * 0 - retry +++ * >0 - ok +++ */ +++static int ffmpeg_get_frame(struct ffmpeg_private *priv) +++{ +++ int res = avcodec_receive_frame(priv->codec_ctx, priv->frame); +++ if (res == AVERROR(EAGAIN)) { +++ av_packet_unref(priv->pkt); +++ res = av_read_frame(priv->format_ctx, priv->pkt); ++ if (res < 0) ++- res = 0; +++ return res; +++ +++ if (priv->pkt->stream_index != priv->stream_index) +++ return 0; ++ ++- output->buffer_pos = output->buffer; ++- output->buffer_used_len = res * sf_get_frame_size(ip_data->sf); +++ priv->curr_size += priv->pkt->size; +++ priv->curr_duration += priv->pkt->duration; ++ ++- av_frame_free(&frame); ++- return output->buffer_used_len; +++ res = avcodec_send_packet(priv->codec_ctx, priv->pkt); +++ if (res == AVERROR(EAGAIN)) +++ return 0; ++ } ++- /* This should never get here. */ ++- return -IP_ERROR_INTERNAL; +++ if (res < 0) +++ return res; +++ +++ int64_t frame_ts = -1; +++ if (priv->frame->pts >= 0) +++ frame_ts = priv->frame->pts; +++ else if (priv->frame->pkt_dts >= 0) +++ frame_ts = priv->frame->pkt_dts; +++ +++ if (priv->seek_ts > 0 && (frame_ts >= 0 || priv->prev_frame_end >= 0)) { +++ if (ffmpeg_seek_into_frame(priv, frame_ts) == 0) +++ return 0; +++ priv->seek_ts = -1; +++ priv->prev_frame_end = -1; +++ } +++ return 1; +++} +++ +++static int ffmpeg_convert_frame(struct ffmpeg_private *priv) +++{ +++ int res = swr_convert(priv->swr, +++ priv->swr_frame->extended_data, +++ /* TODO: proper buffer capacity */ +++ priv->frame->nb_samples, +++ (const uint8_t **)priv->frame->extended_data, +++ priv->frame->nb_samples); +++ if (res >= 0) { +++ priv->swr_frame->nb_samples = res; +++ priv->swr_frame_start = 0; +++ } +++ return res; ++ } ++ ++ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int count) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- struct ffmpeg_output *output = priv->output; ++- int rc; ++- int out_size; ++- ++- if (output->buffer_used_len == 0) { ++- rc = ffmpeg_fill_buffer(ip_data, ++- priv->input_context, priv->codec_context, ++- priv->input, priv->output, priv->swr); ++- if (rc <= 0) ++- return rc; +++ int written = 0; +++ int res; +++ +++ count /= sf_get_frame_size(ip_data->sf); +++ +++ while (count) { +++ if (priv->swr_frame->nb_samples == 0) { +++ res = ffmpeg_get_frame(priv); +++ if (res == AVERROR_EOF) +++ break; +++ else if (res == 0) +++ continue; +++ else if (res < 0) +++ goto err; +++ +++ res = ffmpeg_convert_frame(priv); +++ if (res < 0) +++ goto err; +++ } +++ +++ int copy_frames = min_i(count, priv->swr_frame->nb_samples); +++ int copy_bytes = copy_frames * sf_get_frame_size(ip_data->sf); +++ void *dst = priv->swr_frame->extended_data[0] + priv->swr_frame_start; +++ memcpy(buffer + written, dst, copy_bytes); +++ +++ priv->swr_frame->nb_samples -= copy_frames; +++ priv->swr_frame_start += copy_bytes; +++ count -= copy_frames; +++ written += copy_bytes; ++ } ++- out_size = min_i(output->buffer_used_len, count); ++- memcpy(buffer, output->buffer_pos, out_size); ++- output->buffer_used_len -= out_size; ++- output->buffer_pos += out_size; ++- return out_size; +++ return written; +++err: +++ d_print("%s\n", ffmpeg_errmsg(res)); +++ return -IP_ERROR_INTERNAL; ++ } ++ ++ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- AVStream *st = priv->input_context->streams[priv->input->stream_index]; ++- int ret; +++ AVStream *st = priv->format_ctx->streams[priv->stream_index]; ++ ++- priv->input->seek_ts = offset * AV_TIME_BASE; ++- priv->input->prev_frame_end = -1; +++ priv->seek_ts = offset * AV_TIME_BASE; +++ priv->prev_frame_end = -1; ++ int64_t ts = av_rescale(offset, st->time_base.den, st->time_base.num); ++ ++- avcodec_flush_buffers(priv->codec_context); ++- /* TODO: also flush swresample buffers */ ++- /* Force reading a new packet in next ffmpeg_fill_buffer(). */ ++- priv->input->curr_pkt_size = 0; ++- ++- ret = avformat_seek_file(priv->input_context, ++- priv->input->stream_index, 0, ts, ts, 0); ++- ++- if (ret < 0) { +++ int ret = avformat_seek_file(priv->format_ctx, +++ priv->stream_index, 0, ts, ts, 0); +++ if (ret < 0) ++ return -IP_ERROR_FUNCTION_NOT_SUPPORTED; ++- } else { ++- ffmpeg_buffer_flush(priv->output); ++- return 0; ++- } +++ +++ priv->swr_frame->nb_samples = 0; +++ avcodec_flush_buffers(priv->codec_ctx); +++ /* also flush swresample buffers? */ +++ return 0; ++ } ++ ++ static void ffmpeg_read_metadata(struct growing_keyvals *c, AVDictionary *metadata) ++@@ -445,7 +462,7 @@ static int ffmpeg_read_comments(struct input_plugin_data *ip_data, ++ struct keyval **comments) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- AVFormatContext *ic = priv->input_context; +++ AVFormatContext *ic = priv->format_ctx; ++ ++ GROWING_KEYVALS(c); ++ ++@@ -463,29 +480,29 @@ static int ffmpeg_read_comments(struct input_plugin_data *ip_data, ++ static int ffmpeg_duration(struct input_plugin_data *ip_data) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- return priv->input_context->duration / AV_TIME_BASE; +++ return priv->format_ctx->duration / AV_TIME_BASE; ++ } ++ ++ static long ffmpeg_bitrate(struct input_plugin_data *ip_data) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- long bitrate = priv->input_context->bit_rate; +++ long bitrate = priv->format_ctx->bit_rate; ++ return bitrate ? bitrate : -IP_ERROR_FUNCTION_NOT_SUPPORTED; ++ } ++ ++ static long ffmpeg_current_bitrate(struct input_plugin_data *ip_data) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++- AVStream *st = priv->input_context->streams[priv->input->stream_index]; +++ AVStream *st = priv->format_ctx->streams[priv->stream_index]; ++ long bitrate = -1; ++ /* ape codec returns silly numbers */ ++ if (priv->codec->id == AV_CODEC_ID_APE) ++ return -1; ++- if (priv->input->curr_duration > 0) { ++- double seconds = priv->input->curr_duration * av_q2d(st->time_base); ++- bitrate = (8 * priv->input->curr_size) / seconds; ++- priv->input->curr_size = 0; ++- priv->input->curr_duration = 0; +++ if (priv->curr_duration > 0) { +++ double seconds = priv->curr_duration * av_q2d(st->time_base); +++ bitrate = (8 * priv->curr_size) / seconds; +++ priv->curr_size = 0; +++ priv->curr_duration = 0; ++ } ++ return bitrate; ++ } ++@@ -500,7 +517,7 @@ static char *ffmpeg_codec_profile(struct input_plugin_data *ip_data) ++ { ++ struct ffmpeg_private *priv = ip_data->private; ++ const char *profile; ++- profile = av_get_profile_name(priv->codec, priv->codec_context->profile); +++ profile = av_get_profile_name(priv->codec, priv->codec_ctx->profile); ++ return profile ? xstrdup(profile) : NULL; ++ } ++ diff --cc debian/patches/0007-Validate-sample-format-in-ip_open.patch index 0000000,0000000..aad27c8 new file mode 100644 --- /dev/null +++ b/debian/patches/0007-Validate-sample-format-in-ip_open.patch @@@ -1,0 -1,0 +1,31 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 14:28:46 +0300 ++Subject: Validate sample format in ip_open() ++ ++To prevent segfault in ip_setup() because channels=0, validate ip_data->sf ++after opening ip. ++--- ++ input.c | 10 ++++++++++ ++ 1 file changed, 10 insertions(+) ++ ++diff --git a/input.c b/input.c ++index c20cb3f..f5c5b3c 100644 ++--- a/input.c +++++ b/input.c ++@@ -605,6 +605,16 @@ int ip_open(struct input_plugin *ip) ++ ip_reset(ip, 1); ++ return rc; ++ } +++ +++ unsigned bits = sf_get_bits(ip->data.sf); +++ unsigned channels = sf_get_channels(ip->data.sf); +++ unsigned rate = sf_get_rate(ip->data.sf); +++ if (!bits || !channels || !rate) { +++ d_print("corrupt file: bits = %u, channels = %u, rate = %u\n", +++ bits, channels, rate); +++ return -IP_ERROR_FILE_FORMAT; +++ } +++ ++ ip->open = 1; ++ return 0; ++ } diff --cc debian/patches/0008-ip-ffmpeg-flush-swresample-buffer-when-seeking.patch index 0000000,0000000..89f2cf9 new file mode 100644 --- /dev/null +++ b/debian/patches/0008-ip-ffmpeg-flush-swresample-buffer-when-seeking.patch @@@ -1,0 -1,0 +1,21 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 14:53:52 +0300 ++Subject: ip/ffmpeg: flush swresample buffer when seeking ++ ++--- ++ ip/ffmpeg.c | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 42f630e..775e7de 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -444,7 +444,7 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ ++ priv->swr_frame->nb_samples = 0; ++ avcodec_flush_buffers(priv->codec_ctx); ++- /* also flush swresample buffers? */ +++ swr_convert(priv->swr, NULL, 0, NULL, 0); /* flush swr buffer */ ++ return 0; ++ } ++ diff --cc debian/patches/0009-ip-ffmpeg-remember-swr_frame-s-capacity.patch index 0000000,0000000..e709153 new file mode 100644 --- /dev/null +++ b/debian/patches/0009-ip-ffmpeg-remember-swr_frame-s-capacity.patch @@@ -1,0 -1,0 +1,38 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 15:02:34 +0300 ++Subject: ip/ffmpeg: remember swr_frame's capacity ++ ++--- ++ ip/ffmpeg.c | 5 +++-- ++ 1 file changed, 3 insertions(+), 2 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 775e7de..c659c13 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -49,6 +49,7 @@ struct ffmpeg_private { ++ ++ /* A buffer to hold swr_convert()-ed samples */ ++ AVFrame *swr_frame; +++ int swr_frame_samples_cap; ++ int swr_frame_start; ++ ++ /* Bitrate estimation */ ++@@ -213,6 +214,7 @@ static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv, ++ d_print("av_frame_get_buffer(): %s\n", ffmpeg_errmsg(res)); ++ return -IP_ERROR_INTERNAL; ++ } +++ priv->swr_frame_samples_cap = frame->nb_samples; ++ frame->nb_samples = 0; ++ ++ priv->swr_frame = frame; ++@@ -378,8 +380,7 @@ static int ffmpeg_convert_frame(struct ffmpeg_private *priv) ++ { ++ int res = swr_convert(priv->swr, ++ priv->swr_frame->extended_data, ++- /* TODO: proper buffer capacity */ ++- priv->frame->nb_samples, +++ priv->swr_frame_samples_cap, ++ (const uint8_t **)priv->frame->extended_data, ++ priv->frame->nb_samples); ++ if (res >= 0) { diff --cc debian/patches/0010-ip-ffmpeg-reset-swr_frame_start-when-seeking.patch index 0000000,0000000..fd72b0f new file mode 100644 --- /dev/null +++ b/debian/patches/0010-ip-ffmpeg-reset-swr_frame_start-when-seeking.patch @@@ -1,0 -1,0 +1,20 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 15:54:19 +0300 ++Subject: ip/ffmpeg: reset swr_frame_start when seeking ++ ++--- ++ ip/ffmpeg.c | 1 + ++ 1 file changed, 1 insertion(+) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index c659c13..71cc511 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -444,6 +444,7 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ return -IP_ERROR_FUNCTION_NOT_SUPPORTED; ++ ++ priv->swr_frame->nb_samples = 0; +++ priv->swr_frame_start = 0; ++ avcodec_flush_buffers(priv->codec_ctx); ++ swr_convert(priv->swr, NULL, 0, NULL, 0); /* flush swr buffer */ ++ return 0; diff --cc debian/patches/0011-ip-ffmpeg-better-frame-skipping-logic.patch index 0000000,0000000..cf01f63 new file mode 100644 --- /dev/null +++ b/debian/patches/0011-ip-ffmpeg-better-frame-skipping-logic.patch @@@ -1,0 -1,0 +1,151 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 17:27:20 +0300 ++Subject: ip/ffmpeg: better frame skipping logic ++ ++--- ++ ip/ffmpeg.c | 82 ++++++++++++++++++++++++++++++------------------------------- ++ 1 file changed, 41 insertions(+), 41 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 71cc511..af6ecfb 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -44,8 +44,8 @@ struct ffmpeg_private { ++ ++ AVPacket *pkt; ++ AVFrame *frame; ++- int64_t seek_ts; ++- int64_t prev_frame_end; +++ double seek_ts; +++ int64_t skip_samples; ++ ++ /* A buffer to hold swr_convert()-ed samples */ ++ AVFrame *swr_frame; ++@@ -249,7 +249,6 @@ static int ffmpeg_open(struct input_plugin_data *ip_data) ++ priv.pkt = av_packet_alloc(); ++ priv.frame = av_frame_alloc(); ++ priv.seek_ts = -1; ++- priv.prev_frame_end = -1; ++ ++ priv.swr = swr_alloc(); ++ ffmpeg_set_sf_and_swr_opts(priv.swr, priv.codec_ctx, ++@@ -283,37 +282,37 @@ static int ffmpeg_close(struct input_plugin_data *ip_data) ++ return 0; ++ } ++ ++-/* ++- * return: ++- * 0 - retry ++- * >0 - ok ++- */ ++-static int ffmpeg_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts) +++static int64_t ffmpeg_calc_skip_samples(struct ffmpeg_private *priv) ++ { ++- if (frame_ts >= 0) { ++- AVStream *s = priv->format_ctx->streams[priv->stream_index]; ++- frame_ts = av_rescale_q(frame_ts, s->time_base, AV_TIME_BASE_Q); +++ int64_t ts; +++ if (priv->frame->pts >= 0) { +++ ts = priv->frame->pts; +++ } else if (priv->frame->pkt_dts >= 0) { +++ ts = priv->frame->pkt_dts; ++ } else { ++- frame_ts = priv->prev_frame_end; +++ d_print("AVFrame.pts and AVFrame.pkt_dts are unset\n"); +++ return -1; ++ } ++ ++- if (frame_ts >= priv->seek_ts) ++- return 1; ++- ++- int64_t frame_dur = av_rescale(priv->frame->nb_samples, ++- AV_TIME_BASE, priv->frame->sample_rate); ++- int64_t frame_end = frame_ts + frame_dur; ++- priv->prev_frame_end = frame_end; +++ AVStream *s = priv->format_ctx->streams[priv->stream_index]; +++ double frame_ts = ts * av_q2d(s->time_base); ++ ++- d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n", ++- priv->seek_ts, frame_ts, frame_end); +++ d_print("seek_ts: %.6fs, frame_ts: %.6fs\n", priv->seek_ts, frame_ts); ++ ++- if (frame_end <= priv->seek_ts) +++ if (frame_ts >= priv->seek_ts) ++ return 0; +++ return (priv->seek_ts - frame_ts) * priv->frame->sample_rate; +++} ++ ++- int64_t skip_samples = av_rescale(priv->seek_ts - frame_ts, ++- priv->frame->sample_rate, AV_TIME_BASE); ++- priv->frame->nb_samples -= skip_samples; +++static void ffmpeg_skip_frame_part(struct ffmpeg_private *priv) +++{ +++ if (priv->skip_samples >= priv->frame->nb_samples) { +++ d_print("skipping frame: %d samples\n", +++ priv->frame->nb_samples); +++ priv->skip_samples -= priv->frame->nb_samples; +++ priv->frame->nb_samples = 0; +++ return; +++ } ++ ++ int bps = av_get_bytes_per_sample(priv->frame->format); ++ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100) ++@@ -322,15 +321,17 @@ static int ffmpeg_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts) ++ int channels = priv->codec_ctx->channels; ++ #endif ++ +++ priv->frame->nb_samples -= priv->skip_samples; +++ ++ /* Just modify frame's data pointer because it's throw-away */ ++ if (av_sample_fmt_is_planar(priv->frame->format)) { ++ for (int i = 0; i < channels; i++) ++- priv->frame->extended_data[i] += skip_samples * bps; +++ priv->frame->extended_data[i] += priv->skip_samples * bps; ++ } else { ++- priv->frame->extended_data[0] += skip_samples * channels * bps; +++ priv->frame->extended_data[0] += priv->skip_samples * channels * bps; ++ } ++- d_print("skipping %ld samples\n", skip_samples); ++- return 1; +++ d_print("skipping %ld samples\n", priv->skip_samples); +++ priv->skip_samples = 0; ++ } ++ ++ /* ++@@ -361,17 +362,16 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv) ++ if (res < 0) ++ return res; ++ ++- int64_t frame_ts = -1; ++- if (priv->frame->pts >= 0) ++- frame_ts = priv->frame->pts; ++- else if (priv->frame->pkt_dts >= 0) ++- frame_ts = priv->frame->pkt_dts; +++ if (priv->seek_ts > 0) { +++ priv->skip_samples = ffmpeg_calc_skip_samples(priv); +++ if (priv->skip_samples >= 0) +++ priv->seek_ts = -1; +++ } ++ ++- if (priv->seek_ts > 0 && (frame_ts >= 0 || priv->prev_frame_end >= 0)) { ++- if (ffmpeg_seek_into_frame(priv, frame_ts) == 0) +++ if (priv->skip_samples > 0) { +++ ffmpeg_skip_frame_part(priv); +++ if (priv->frame->nb_samples == 0) ++ return 0; ++- priv->seek_ts = -1; ++- priv->prev_frame_end = -1; ++ } ++ return 1; ++ } ++@@ -434,8 +434,8 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) ++ struct ffmpeg_private *priv = ip_data->private; ++ AVStream *st = priv->format_ctx->streams[priv->stream_index]; ++ ++- priv->seek_ts = offset * AV_TIME_BASE; ++- priv->prev_frame_end = -1; +++ priv->seek_ts = offset; +++ priv->skip_samples = 0; ++ int64_t ts = av_rescale(offset, st->time_base.den, st->time_base.num); ++ ++ int ret = avformat_seek_file(priv->format_ctx, diff --cc debian/patches/0012-ip-ffmpeg-don-t-process-empty-frames.patch index 0000000,0000000..a52c31c new file mode 100644 --- /dev/null +++ b/debian/patches/0012-ip-ffmpeg-don-t-process-empty-frames.patch @@@ -1,0 -1,0 +1,21 @@@ ++From: ihy123 ++Date: Sun, 17 Aug 2025 19:22:50 +0300 ++Subject: ip/ffmpeg: don't process empty frames ++ ++--- ++ ip/ffmpeg.c | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index af6ecfb..dd9061a 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -356,7 +356,7 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv) ++ priv->curr_duration += priv->pkt->duration; ++ ++ res = avcodec_send_packet(priv->codec_ctx, priv->pkt); ++- if (res == AVERROR(EAGAIN)) +++ if (res == 0 || res == AVERROR(EAGAIN)) ++ return 0; ++ } ++ if (res < 0) diff --cc debian/patches/0013-ip-ffmpeg-improve-readability.patch index 0000000,0000000..cdad99c new file mode 100644 --- /dev/null +++ b/debian/patches/0013-ip-ffmpeg-improve-readability.patch @@@ -1,0 -1,0 +1,111 @@@ ++From: ihy123 ++Date: Mon, 18 Aug 2025 03:32:22 +0300 ++Subject: ip/ffmpeg: improve readability ++ ++Previously ffmpeg_read()'s while loop was kinda leaking into ++ffmpeg_get_frame(), now it doesn't. ++--- ++ ip/ffmpeg.c | 36 ++++++++++++++++++++---------------- ++ 1 file changed, 20 insertions(+), 16 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index dd9061a..fc74895 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -337,30 +337,32 @@ static void ffmpeg_skip_frame_part(struct ffmpeg_private *priv) ++ /* ++ * return: ++ * <0 - error ++- * 0 - retry +++ * 0 - eof ++ * >0 - ok ++ */ ++ static int ffmpeg_get_frame(struct ffmpeg_private *priv) ++ { ++- int res = avcodec_receive_frame(priv->codec_ctx, priv->frame); +++ int res; +++retry: +++ res = avcodec_receive_frame(priv->codec_ctx, priv->frame); ++ if (res == AVERROR(EAGAIN)) { ++ av_packet_unref(priv->pkt); ++ res = av_read_frame(priv->format_ctx, priv->pkt); ++ if (res < 0) ++- return res; +++ goto err; ++ ++ if (priv->pkt->stream_index != priv->stream_index) ++- return 0; +++ goto retry; ++ ++ priv->curr_size += priv->pkt->size; ++ priv->curr_duration += priv->pkt->duration; ++ ++ res = avcodec_send_packet(priv->codec_ctx, priv->pkt); ++ if (res == 0 || res == AVERROR(EAGAIN)) ++- return 0; +++ goto retry; ++ } ++ if (res < 0) ++- return res; +++ goto err; ++ ++ if (priv->seek_ts > 0) { ++ priv->skip_samples = ffmpeg_calc_skip_samples(priv); ++@@ -371,9 +373,14 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv) ++ if (priv->skip_samples > 0) { ++ ffmpeg_skip_frame_part(priv); ++ if (priv->frame->nb_samples == 0) ++- return 0; +++ goto retry; ++ } ++ return 1; +++err: +++ if (res == AVERROR_EOF) +++ return 0; +++ d_print("%s\n", ffmpeg_errmsg(res)); +++ return -IP_ERROR_INTERNAL; ++ } ++ ++ static int ffmpeg_convert_frame(struct ffmpeg_private *priv) ++@@ -386,8 +393,10 @@ static int ffmpeg_convert_frame(struct ffmpeg_private *priv) ++ if (res >= 0) { ++ priv->swr_frame->nb_samples = res; ++ priv->swr_frame_start = 0; +++ return res; ++ } ++- return res; +++ d_print("%s\n", ffmpeg_errmsg(res)); +++ return -IP_ERROR_INTERNAL; ++ } ++ ++ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int count) ++@@ -401,16 +410,14 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun ++ while (count) { ++ if (priv->swr_frame->nb_samples == 0) { ++ res = ffmpeg_get_frame(priv); ++- if (res == AVERROR_EOF) +++ if (res == 0) ++ break; ++- else if (res == 0) ++- continue; ++ else if (res < 0) ++- goto err; +++ return res; ++ ++ res = ffmpeg_convert_frame(priv); ++ if (res < 0) ++- goto err; +++ return res; ++ } ++ ++ int copy_frames = min_i(count, priv->swr_frame->nb_samples); ++@@ -424,9 +431,6 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun ++ written += copy_bytes; ++ } ++ return written; ++-err: ++- d_print("%s\n", ffmpeg_errmsg(res)); ++- return -IP_ERROR_INTERNAL; ++ } ++ ++ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset) diff --cc debian/patches/0014-ip-ffmpeg-fix-building-for-ffmpeg-8.0.patch index 0000000,0000000..99bd845 new file mode 100644 --- /dev/null +++ b/debian/patches/0014-ip-ffmpeg-fix-building-for-ffmpeg-8.0.patch @@@ -1,0 -1,0 +1,24 @@@ ++From: ihy123 ++Date: Sun, 24 Aug 2025 19:16:57 +0300 ++Subject: ip/ffmpeg: fix building for ffmpeg 8.0 ++ ++avcodec_close() can be safely removed because avcodec_free_context() ++is its replacement since 2016. See ffmpeg commit 2ef6dab0a79 ++ ++Builds with v3.3.9 v4.0.6 v6.1.3 v7.1.1 v8.0 ++--- ++ ip/ffmpeg.c | 1 - ++ 1 file changed, 1 deletion(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index fc74895..2cb0767 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -223,7 +223,6 @@ static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv, ++ ++ static void ffmpeg_free(struct ffmpeg_private *priv) ++ { ++- avcodec_close(priv->codec_ctx); ++ avcodec_free_context(&priv->codec_ctx); ++ avformat_close_input(&priv->format_ctx); ++ diff --cc debian/patches/0015-ip-ffmpeg-change-sample-format-conversions.patch index 0000000,0000000..5235212 new file mode 100644 --- /dev/null +++ b/debian/patches/0015-ip-ffmpeg-change-sample-format-conversions.patch @@@ -1,0 -1,0 +1,30 @@@ ++From: ihy123 ++Date: Mon, 25 Aug 2025 11:17:06 +0300 ++Subject: ip/ffmpeg: change sample format conversions ++ ++--- ++ ip/ffmpeg.c | 10 ++++------ ++ 1 file changed, 4 insertions(+), 6 deletions(-) ++ ++diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c ++index 2cb0767..2d3c610 100644 ++--- a/ip/ffmpeg.c +++++ b/ip/ffmpeg.c ++@@ -157,13 +157,11 @@ static void ffmpeg_set_sf_and_swr_opts(SwrContext *swr, AVCodecContext *cc, ++ av_opt_set_int(swr, "in_sample_rate", cc->sample_rate, 0); ++ av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); ++ ++- *out_sample_fmt = cc->sample_fmt; ++- switch (*out_sample_fmt) { ++- case AV_SAMPLE_FMT_U8: ++- sf |= sf_bits(8) | sf_signed(0); ++- break; ++- case AV_SAMPLE_FMT_S32: +++ switch (cc->sample_fmt) { +++ case AV_SAMPLE_FMT_FLT: case AV_SAMPLE_FMT_FLTP: +++ case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P: ++ sf |= sf_bits(32) | sf_signed(1); +++ *out_sample_fmt = AV_SAMPLE_FMT_S32; ++ break; ++ default: ++ sf |= sf_bits(16) | sf_signed(1); diff --cc debian/patches/series index 0000000,0000000..c78695c new file mode 100644 --- /dev/null +++ b/debian/patches/series @@@ -1,0 -1,0 +1,15 @@@ ++0001-atomic_ld.patch ++0002-fix-blhc.patch ++0003-ip-ffmpeg-more-precise-seeking.patch ++0004-ip-ffmpeg-skip-samples-only-when-needed.patch ++0005-ip-ffmpeg-remove-excessive-version-checks.patch ++0006-ip-ffmpeg-major-refactor.patch ++0007-Validate-sample-format-in-ip_open.patch ++0008-ip-ffmpeg-flush-swresample-buffer-when-seeking.patch ++0009-ip-ffmpeg-remember-swr_frame-s-capacity.patch ++0010-ip-ffmpeg-reset-swr_frame_start-when-seeking.patch ++0011-ip-ffmpeg-better-frame-skipping-logic.patch ++0012-ip-ffmpeg-don-t-process-empty-frames.patch ++0013-ip-ffmpeg-improve-readability.patch ++0014-ip-ffmpeg-fix-building-for-ffmpeg-8.0.patch ++0015-ip-ffmpeg-change-sample-format-conversions.patch diff --cc debian/rules index 0000000,0000000..765979d new file mode 100755 --- /dev/null +++ b/debian/rules @@@ -1,0 -1,0 +1,59 @@@ ++#!/usr/bin/make -f ++# -*- makefile -*- ++ ++include /usr/share/dpkg/architecture.mk ++ifneq ($(DEB_BUILD_ARCH),$(DEB_HOST_ARCH)) ++CROSS = CROSS=$(DEB_HOST_GNU_TYPE)- PKG_CONFIG=$(DEB_HOST_GNU_TYPE)-pkg-config ++endif ++ ++# The following architectures need the -latomic flag ++# to build, otherwise we FTBFS with ++# ./track_info.c:47: undefined reference to `__atomic_fetch_add_8' ++# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=935678 ++# Depends on 13-atomic_ld.patch ++ifneq (,$(findstring $(DEB_HOST_ARCH), armel m68k mipsel powerpc sh4)) ++export LDLIBS += -latomic ++endif ++ ++DEB_CFLAGS_MAINT_APPEND += -I/usr/include/ncursesw ++DEB_BUILD_MAINT_OPTIONS = hardening=+all ++DPKG_EXPORT_BUILDFLAGS = 1 ++include /usr/share/dpkg/buildflags.mk ++ ++suggested_deps = pulse jack ++ ++EXTRA_CMUS_DIR_OP_PLUGINS = debian/cmus/usr/lib/cmus/op/ ++EXTRA_CMUS_PLUGINS := $(foreach plugin,$(suggested_deps),$(plugin).so) ++ ++%: ++ dh $@ --with bash-completion ++ ++override_dh_auto_configure: ++ $(CROSS) ./configure \ ++ prefix=/usr \ ++ CONFIG_ARTS=n \ ++ CONFIG_ROAR=n \ ++ DEBUG=0 ++ ++override_dh_auto_build: ++ # Pass V=2 to make to enable verbose build logs, which is useful for ++ # porters, sorting out build hardening issues, etc. ++ dh_auto_build -- V=2 ++ ++override_dh_install: ++ dh_install -pcmus ++ dh_movefiles -pcmus-plugin-ffmpeg --sourcedir=debian/cmus/ \ ++ /usr/lib/cmus/ip/ffmpeg.so ++ ++override_dh_installdocs: ++ dh_installdocs ++ # do not install zsh and bash completion twice ++ rm debian/cmus/usr/share/doc/cmus/contrib/_cmus \ ++ debian/cmus/usr/share/doc/cmus/contrib/cmus.bash-completion ++ ++override_dh_shlibdeps: ++ dh_shlibdeps -pcmus $(foreach plugin,$(EXTRA_CMUS_PLUGINS),-X$(plugin)) ++ dpkg-shlibdeps -O -dSuggests \ ++ $(foreach plugin,$(EXTRA_CMUS_PLUGINS),$(EXTRA_CMUS_DIR_OP_PLUGINS)$(plugin)) \ ++ >> debian/cmus.substvars ++ dh_shlibdeps --remaining-packages diff --cc debian/salsa-ci.yml index 0000000,0000000..8424db4 new file mode 100644 --- /dev/null +++ b/debian/salsa-ci.yml @@@ -1,0 -1,0 +1,3 @@@ ++--- ++include: ++ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml diff --cc debian/source/format index 0000000,0000000..163aaf8 new file mode 100644 --- /dev/null +++ b/debian/source/format @@@ -1,0 -1,0 +1,1 @@@ ++3.0 (quilt) diff --cc debian/upstream/metadata index 0000000,0000000..7d5f13d new file mode 100644 --- /dev/null +++ b/debian/upstream/metadata @@@ -1,0 -1,0 +1,4 @@@ ++Bug-Database: https://github.com/cmus/cmus/issues ++Bug-Submit: https://github.com/cmus/cmus/issues/new ++Repository: https://github.com/cmus/cmus.git ++Repository-Browse: https://github.com/cmus/cmus diff --cc debian/watch index 0000000,0000000..dca9c32 new file mode 100644 --- /dev/null +++ b/debian/watch @@@ -1,0 -1,0 +1,3 @@@ ++version=4 ++opts="dversionmangle=s/\+git\d+$//,uversionmangle=s/([\d\.]+)-(rc|beta)(.*)/\1~\2\3/,filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/cmus-$1\.tar\.gz/" \ ++https://github.com/cmus/cmus/tags .*/v?(\d\S*)\.tar\.gz